www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - why does isForwardRange work like this?

reply "Vlad Levenfeld" <vlevenfeld gmail.com> writes:
I've been having trouble propagating range traits for 
range-wrapper structs.

Consider this sample code:

struct Wrapper (R)
{
	R range;

	static if (isInputRange!R)
	{
		/* input range stuff */
	}
	static if (isForwardRange!R)
	{
		auto save () inout
		{
			return this;
		}

		static assert (isForwardRange!Wrapper); // <-- this fails
	}
}

making save  property makes it compile.

So I looked at the implementation of isForwardRange and now I am 
very confused about this condition:

is(typeof((inout int = 0)
     {
         R r1 = void;
         static assert (is(typeof(r1.save) == R));
     }));

What's the rationale behind stating the condition this way as 
opposed to, say,

is (typeof(R.init.save)) == R) || is ((typeof(R.init.save()) == R)

so that member fields as well as  property and non- property 
methods will match, and what is the purpose of (inout int = 0)?
Jul 31 2014
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Thursday, 31 July 2014 at 20:34:42 UTC, Vlad Levenfeld wrote:
 What's the rationale behind stating the condition this way as 
 opposed to, say,

 is (typeof(R.init.save)) == R) || is ((typeof(R.init.save()) == 
 R)

 so that member fields as well as  property and non- property 
 methods will match
save should never have been a property, since it doesn't really emulate a variable, but because it was decided that it was a property, it is required by the API that it be a property. And the reason why it's required to be a property once it was decided that it should be one is quite simple. What would happen if you a function did this auto s = range.save(); and save was a property? The code would fail to compile. Because it was decided that save should be a property, _every_ time that save is used, it must be used as a property, or it won't work with any range that did define save as a property. As such, there is no reason to allow save to be a non-property function. Allowing that would just make it easier to write code which called save incorrectly but worked with the ranges that it was tested with (because they defined save as a function instead of a property). In addition, if it works with your range, it's perfectly legal to define save as a member variable (though that would be a rather bizarre thing to do), and allowing save to be called as a function by the range API would break that. So, once it's been decided that it's legal for something in a templated API to be a property, it _must_ be a property, a variable, or an enum, or there are going to be problems, because it has to be used without parens. - Jonathan M Davis
Jul 31 2014
parent reply "Vlad Levenfeld" <vlevenfeld gmail.com> writes:
Yes, I see the problem now. I can't think of any reason why I'd 
want to make save anything but a function (especially since 
`save` is a verb) but I guess someone out there might have a good 
one.

So, what is gained by (inout int = 0) over ()? I wasn't even 
aware that giving a default value for an unlabeled parameter 
would compile. What does it do?
Jul 31 2014
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Thursday, 31 July 2014 at 22:21:10 UTC, Vlad Levenfeld wrote:
 Yes, I see the problem now. I can't think of any reason why I'd 
 want to make save anything but a function (especially since 
 `save` is a verb) but I guess someone out there might have a 
 good one.
It's Andrei's fault. I'm not quite sure what he was thinking. But unfortunately, we're stuck with it. So, it's just become one of D's little quirks that we have to learn and live with.
 So, what is gained by (inout int = 0) over ()? I wasn't even 
 aware that giving a default value for an unlabeled parameter 
 would compile. What does it do?
I've wondered that myself but never taken the time to look into it. However, according to this post: http://forum.dlang.org/post/mailman.102.1396007039.25518.digitalmars-d-learn puremagic.com it looks like it convinces the compiler to make the function an inout function so that the range variable that's declared can be treated as inout and therefore be able to have ranges with inout in their type work.
Jul 31 2014
parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Friday, 1 August 2014 at 04:52:35 UTC, Jonathan M Davis wrote:
 On Thursday, 31 July 2014 at 22:21:10 UTC, Vlad Levenfeld wrote:
 Yes, I see the problem now. I can't think of any reason why 
 I'd want to make save anything but a function (especially 
 since `save` is a verb) but I guess someone out there might 
 have a good one.
It's Andrei's fault. I'm not quite sure what he was thinking. But unfortunately, we're stuck with it. So, it's just become one of D's little quirks that we have to learn and live with.
Can we not at least deprecate it? And while we're at it, the same for `dup` and `idup`?
Aug 01 2014
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, 1 August 2014 at 11:51:55 UTC, Marc Sch├╝tz wrote:
 On Friday, 1 August 2014 at 04:52:35 UTC, Jonathan M Davis 
 wrote:
 On Thursday, 31 July 2014 at 22:21:10 UTC, Vlad Levenfeld 
 wrote:
 Yes, I see the problem now. I can't think of any reason why 
 I'd want to make save anything but a function (especially 
 since `save` is a verb) but I guess someone out there might 
 have a good one.
It's Andrei's fault. I'm not quite sure what he was thinking. But unfortunately, we're stuck with it. So, it's just become one of D's little quirks that we have to learn and live with.
Can we not at least deprecate it? And while we're at it, the same for `dup` and `idup`?
It would break too much code to change save at this point. There's no way that you're going to talk Andrei or Walter into changing something like that over whether it makes sense for it to be a property or not. That's not the kind of thing that they think is important, and you're more likely to get Andrei to try and kill of property again rather than anything useful. As for dup and idup, they were replaced with functions recently (maybe for 2.066 but not 2.065 - i'm not sure when the changes were made), so they might actually work with parens now. I'm not sure. But since dup and idup aren't being implemented by lots of different people like the range API is, changing those doesn't risk breaking code where folks made it a variable. - Jonathan M Davis
Aug 01 2014
parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, 1 August 2014 at 19:59:16 UTC, Jonathan M Davis wrote:
 But since dup and idup aren't being implemented by lots of 
 different people like the range API is, changing those doesn't 
 risk breaking code where folks made it a variable.
Well, I probably shouldn't put it quite that way, since that's not the only problem with changing save (which I guess that that statement implies). The real problem with changing save is that we'd have to change the template constraint to use save() to make sure that no one declared it as a variable, and that would break everyone's code who declared save as a property - so, everyone. And _that_ is why save isn't going to change. - Jonathan M Davis
Aug 01 2014