www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - nested inout return type

reply Simon =?UTF-8?B?QsO8cmdlcg==?= <simon.buerger rwth-aachen.de> writes:
I'm writing a custom (originally multi-dimensional) Slice-type, 
analogous to the builtin T[], and stumbled upon the problem that 
the following code won't compile. The workaround is simple: just 
write the function three times for mutable/const/immutable. But 
as "inout" was invented to make that unneccessary I was wondering 
if there is a clever way to make this work.


struct Slice(T)
{
     T* ptr;
     size_t length;

     Slice!(inout(T)) opSlice(size_t a, size_t b) inout
     {
         return Slice!(inout(T))(ptr+a, b-a);
     }
}
Jun 13 2016
parent reply Era Scarecrow <rtcvb32 yahoo.com> writes:
On Monday, 13 June 2016 at 22:31:00 UTC, Simon Bürger wrote:
 But as "inout" was invented to make that unneccessary I was 
 wondering if there is a clever way to make this work.

     <snip>

     Slice!(inout(T)) opSlice(size_t a, size_t b) inout
     {
         return Slice!(inout(T))(ptr+a, b-a);
     }
Hmmm. Wouldn't just returning an inout of the Slice work? Otherwise you'll get inner template instantiation and that can be annoying inout(Slice) opSlice(size_t a, size_t b) inout { return cast(inout(Slice)) Slice(ptr+a, b-a); }
Jun 13 2016
parent reply Era Scarecrow <rtcvb32 yahoo.com> writes:
On Monday, 13 June 2016 at 23:51:40 UTC, Era Scarecrow wrote:
      inout(Slice) opSlice(size_t a, size_t b) inout
      {
          return cast(inout(Slice)) Slice(ptr+a, b-a);
      }
Seems the pointer has to be force-cast back to a normal pointer so the constructor can work. (Because the function is inout, ptr becomes inout(T*) ) return cast(inout(Slice)) Slice(cast(T*)ptr+a, b-a); Beyond that it works as expected :) Writeln gives the following output on Slice with opSlices: Slice!int(18FD60, 10) const(Slice!int)(18FD60, 10) immutable(Slice!int)(18FD90, 10)
Jun 13 2016
parent reply Simon =?UTF-8?B?QsO8cmdlcg==?= <simon.buerger rwth-aachen.de> writes:
On Tuesday, 14 June 2016 at 01:50:17 UTC, Era Scarecrow wrote:
 On Monday, 13 June 2016 at 23:51:40 UTC, Era Scarecrow wrote:
      inout(Slice) opSlice(size_t a, size_t b) inout
      {
          return cast(inout(Slice)) Slice(ptr+a, b-a);
      }
Seems the pointer has to be force-cast back to a normal pointer so the constructor can work. (Because the function is inout, ptr becomes inout(T*) ) return cast(inout(Slice)) Slice(cast(T*)ptr+a, b-a); Beyond that it works as expected :) Writeln gives the following output on Slice with opSlices: Slice!int(18FD60, 10) const(Slice!int)(18FD60, 10) immutable(Slice!int)(18FD90, 10)
Then instead of Slice!(const(T)) one would use const(Slice!T). Then there is no analogue of the following: const(T)[] s = ... s = s[5..7] which is quite common when parsing strings for example. Still, might be the cleanest approach. However I found another solution for now without using any "inout": * only do one mutable version of opSlice * add implicit cast (using "alias this") for const(Slice!T) -> Slice!(const(T)). So when trying to opSlice on a const it will first cast to a mutable-slice-of-const-elements and then do the slice. This is closer to the behavior of "const(T[])", though it might have issues when using immutable and not only const. Not sure. Anyway, thanks for the help, and if someone cares, the full resulting code is on github.com/Krox/jive/blob/master/jive/array.d
Jun 14 2016
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 6/14/16 9:22 AM, Simon Bürger wrote:
 On Tuesday, 14 June 2016 at 01:50:17 UTC, Era Scarecrow wrote:
 On Monday, 13 June 2016 at 23:51:40 UTC, Era Scarecrow wrote:
      inout(Slice) opSlice(size_t a, size_t b) inout
      {
          return cast(inout(Slice)) Slice(ptr+a, b-a);
      }
Seems the pointer has to be force-cast back to a normal pointer so the constructor can work. (Because the function is inout, ptr becomes inout(T*) ) return cast(inout(Slice)) Slice(cast(T*)ptr+a, b-a);
Better: inout(Slice)(ptr+a, b-a);
 Then instead of Slice!(const(T)) one would use const(Slice!T). Then
 there is no analogue of the following:

 const(T)[] s = ...
 s = s[5..7]
Yes, this is a missing piece of the language. In order to use custom types, you must give up tail modifiers.
 which is quite common when parsing strings for example. Still, might be
 the cleanest approach. However I found another solution for now without
 using any "inout":

 * only do one mutable version of opSlice
 * add implicit cast (using "alias this") for const(Slice!T) ->
 Slice!(const(T)).
Interesting, but unfortunately, the compiler isn't eager about this conversion. auto x = s[5 .. 7] isn't going to give you a Slice!(const(T)), like an array would. But I like the idea. And of course, there is the issue of not allowing structs with inout members. So really you need to triplicate the function for all the modifiers. And of course, alias this can only be used once... -Steve
Jun 14 2016
next sibling parent Simon =?UTF-8?B?QsO8cmdlcg==?= <simon.buerger rwth-aachen.de> writes:
On Tuesday, 14 June 2016 at 14:47:11 UTC, Steven Schveighoffer 
wrote:
 * only do one mutable version of opSlice
 * add implicit cast (using "alias this") for const(Slice!T) ->
 Slice!(const(T)).
Interesting, but unfortunately, the compiler isn't eager about this conversion. auto x = s[5 .. 7] isn't going to give you a Slice!(const(T)), like an array would. But I like the idea.
Hm, you are right, in fact it doesn't work. Somehow it seemed to in my usecase. Well, triplicate it is then. Which isn't that bad using something like auto opSlice(size_t a, size_t b) { // actual non-trivial code } auto opSlice(size_t a, size_t b) const { return Slice!(const(T))(ptr, length).opSlice(a,b); } auto opSlice(size_t a, size_t b) immutable { return Slice!(immutable(T))(ptr, length).opSlice(a,b); }
Jun 14 2016
prev sibling parent reply Era Scarecrow <rtcvb32 yahoo.com> writes:
On Tuesday, 14 June 2016 at 14:47:11 UTC, Steven Schveighoffer 
wrote:
 On Tuesday, 14 June 2016 at 01:50:17 UTC, Era Scarecrow wrote:
      return cast(inout(Slice)) Slice(cast(T*)ptr+a, b-a);
Better: inout(Slice)(ptr+a, b-a);
Of course... My amateur D-fu skills show themselves. cast() const() immutable() are the same, why not inout? Hmmm... Reminds me when I didn't understand how to get the address or use pointers correctly, so I'd do stuff like &ptr[i] everywhere because no one told me a better way to do it. I also remember seeing odd issues and bugs in C when using a char and then having negative numbers so having to use & 0xff flags everywhere until I added the _unsigned_ keyword in. I feel like a tutorial for common problems and solutions should be present for C, C++ & D. Then again maybe that's some cookbooks that I haven't purchased/read yet.
Jun 14 2016
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 6/14/16 3:38 PM, Era Scarecrow wrote:
 On Tuesday, 14 June 2016 at 14:47:11 UTC, Steven Schveighoffer wrote:
 On Tuesday, 14 June 2016 at 01:50:17 UTC, Era Scarecrow wrote:
      return cast(inout(Slice)) Slice(cast(T*)ptr+a, b-a);
Better: inout(Slice)(ptr+a, b-a);
Of course... My amateur D-fu skills show themselves. cast() const() immutable() are the same, why not inout? Hmmm...
It's mostly akin to immutable (which would require similar syntax). It's because once constructed, inout-flavored wrappers cannot change anything internally. So you have to do it all at once. const is different, because you can construct mutable, and then simply cast to const when you feel like it. But of course, if the components you are using to construct are already flavored, you have no choice. All-at-once construction is the only way without casting.
  I feel like a tutorial for common problems and solutions should be
 present for C, C++ & D. Then again maybe that's some cookbooks that I
 haven't purchased/read yet.
For a long time I have been working on an article to talk about the quirks/tricks of inout. I gave a talk at dconf, but there are more things to show than are possible in a spoken talk. I honestly think the best place to go figure these things out is stackoverflow (or just the internet in general). Whenever I have a technical problem I can't figure out (or am too lazy to diagnose myself), I search and SO usually gives me an answer :) -Steve
Jun 14 2016
parent Era Scarecrow <rtcvb32 yahoo.com> writes:
On Tuesday, 14 June 2016 at 19:48:06 UTC, Steven Schveighoffer 
wrote:
 I honestly think the best place to go figure these things out 
 is stackoverflow (or just the internet in general). Whenever I 
 have a technical problem I can't figure out (or am too lazy to 
 diagnose myself), I search and SO usually gives me an answer :)
For the longest time I didn't have internet consistently, so I often had to figure these things out solo and alone. Honestly I'm still new to figuring out where things are on the internet, or what I need and don't need. Doesn't help being self taught means I don't know some of the lingo. What is map? What does reduce do? What's a HashMap? These things by themselves (to someone relatively new) doesn't make sense, and the STL and C++ seem to actively push me away from understanding it so I dropped them wholesale. The only libraries that made sense and I would rely on were the bare minimum core library ones included in the '88 CPL including bare minimum string and IO functions. Perhaps that's why I'm still shy about learning some of the libraries and understanding some of the more ingenious solutions that can be written in a couple lines rather than building my own solution which is clunky (but better than C++). Although I'm doing better than I used to, it's still a chore. :(
Jun 14 2016