June 23, 2015
On Tue, Jun 23, 2015 at 4:49 PM, Vladimir Panteleev via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On Tuesday, 23 June 2015 at 23:17:54 UTC, Meta wrote:
>
>> I really hate this naming scheme for functions that take lazy parameters. I still don't see why we don't do the (IMO) simplest and most intuitive thing and name them lazyToLower / lazyToUpper (or toLowerLazy / toUpperLazy). There is precedent with C#'s handling of async functions; for example, AccessTheWebAsync or GetStringAsync[1]. Your proposed naming scheme seems like it's trying to be too "clever" and really just ends up causing unnecessary confusion. This is not Ruby. [1]https://msdn.microsoft.com/en-us/library/hh191443.aspx
>>
>
> I'm not sure about this... I've seen another proposal for a "lazy" suffix in the other thread, but I think this won't be great in the long run:
>
> - Ultimately, we want to encourage use of the lazy versions, in the same way that e.g. std.algorithm and std.range are encouraged over eager operations for arrays.
>
> - There is no consistency with any existing naming schemes. Currently no names in Phobos contain the word "Lazy".
>
> - If std.algorithm were to follow this convention, it would have lazyJoin instead of joiner, lazySplit instead of splitter, lazyConcat OSLT instead of chain, etc. Given a typical program using std.algorithm, do you think such names would look better there than the current ones?
>
> - I'm not sure about the C# async analogy: with "async", the methods are used in a different way. The new range-based functions are used in the same way, but work on different types.
>
> Here's an example program using setExt[ension] and toLower[Case], in 4 variants...
>
> https://gist.github.com/CyberShadow/5cc7e926f566d56a672f
>
> IMHO, in this case, the "Lazy" suffix is a distracting technicality that doesn't carry its weight. Am I the only one?
>
>
+1

If I'd seen this two minutes ago could have saved me some typing.


June 23, 2015
On Tue, Jun 23, 2015 at 4:33 PM, Mike via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On Tuesday, 23 June 2015 at 22:45:10 UTC, Vladimir Panteleev wrote:
>
>  Sounds good?
>>
>
> Yes, please note that although I suggested a `Lazy` suffix, I don't want it to be a convention.  It should only be used as a disambiguator when ambiguity arises.
>

This would make it a convention.  And a poor one, as it basically says 'do
your own thing, but if you do something confusing stick lazy on the end.'
 Better in my opinion to have a convention that covers things in the first
place, so you never get to the point where differentiating via 'lazy' seems
like a good idea.


I actually don't think having separate threads for each name is the best solution.  May be better to get them all listed in one place, and see if a consistent naming system can emerge.


June 23, 2015
On Tuesday, 23 June 2015 at 23:49:45 UTC, Vladimir Panteleev wrote:
> - Ultimately, we want to encourage use of the lazy versions, in the same way that e.g. std.algorithm and std.range are encouraged over eager operations for arrays.

Another point: the range-ification of Phobos is only going to continue. This means that, should this scheme be followed, the number of functions with "Lazy" in the same is only going to grow, and as these functions are intended to become the canonical way to write modern D, so will the number of occurrences of "Lazy" in a typical canonical D program. I think this is a strong argument for avoiding "Lazy", at least for functions which intend to displace their eager counterparts.
June 24, 2015
On Tuesday, 23 June 2015 at 23:58:52 UTC, Vladimir Panteleev wrote:
> On Tuesday, 23 June 2015 at 23:49:45 UTC, Vladimir Panteleev wrote:
>> - Ultimately, we want to encourage use of the lazy versions, in the same way that e.g. std.algorithm and std.range are encouraged over eager operations for arrays.
>
> Another point: the range-ification of Phobos is only going to continue. This means that, should this scheme be followed, the number of functions with "Lazy" in the same is only going to grow, and as these functions are intended to become the canonical way to write modern D, so will the number of occurrences of "Lazy" in a typical canonical D program. I think this is a strong argument for avoiding "Lazy", at least for functions which intend to displace their eager counterparts.

But now you are going to have to come up with a clever name for every replacement and the clarity of each will be shoty at best. The append lazy convention at least is a convention that is very clear, the other way has no rules, you just are making up new names.
June 24, 2015
On Tuesday, 23 June 2015 at 23:58:52 UTC, Vladimir Panteleev wrote:
> On Tuesday, 23 June 2015 at 23:49:45 UTC, Vladimir Panteleev wrote:
>> - Ultimately, we want to encourage use of the lazy versions, in the same way that e.g. std.algorithm and std.range are encouraged over eager operations for arrays.
>
> Another point: the range-ification of Phobos is only going to continue. This means that, should this scheme be followed, the number of functions with "Lazy" in the same is only going to grow, and as these functions are intended to become the canonical way to write modern D, so will the number of occurrences of "Lazy" in a typical canonical D program. I think this is a strong argument for avoiding "Lazy", at least for functions which intend to displace their eager counterparts.

Ok, I'm with you.  Allow me to offer another suggestion then.

1. Add functions `toUpperCaseEager` and `toLowerCaseEager`.
2. Have `toUpper` forward to `toUpperCaseEager` and `toLower` forward to `toLowerCaseEager` with a friendly comment.  You don't need to deprecate `toUpper` or `toLower` unless you want to.  It will happen naturally and gradually in time anyway.
3. Add functions `toUpperCase` and `toLowerCase` implementing the lazy versions.

Something similar could also be applied to `setExtension`
1. Add `setExt` implementing the lazy version and `setExtEager` implementing the eager version
2. Forward `setExtension` to `setExtEager` with a friendly comment.  Again, you don't need to deprecate `setExtension` unless you want to.  It will happen naturally and gradually in time anyway.

If this only makes things worse in your opinion, go with `withExtension` and your other suggestions.  I'm already weary of this.

Mike
June 24, 2015
We disagreed on this on irc, but I ask you to consider the following which limits the code breakage a lot more than my first proposal in chat:

---

import std.range;

struct ToLowered(R) if(isInputRange!R) {
	R inputRange;
	this(R r) {
		static if(isForwardRange!R)
			inputRange = r;
		if(!empty)
			front = cast(char) (inputRange.front | 0x20);
	}

	char front;

	static if(isForwardRange!R)
	typeof(this) save() { return this; }

	bool empty() {
		return inputRange.empty();
	}

	void popFront() {
		inputRange.popFront();
		if(!empty)
			front = cast(char) (inputRange.front | 0x20);
	}

	private immutable(char)[] eagerCache;
	deprecated("please call .array on this yourself or adjust your algorithm to use the laziness (tip: changing string declarations to auto may help)")
	string eager() pure {
		if(eagerCache is null) {
			foreach(c; this)
				eagerCache ~= c;
		}
		return eagerCache;
	}

 	alias eager this;
}

ToLowered!R toLower(R)(R r) {
	return ToLowered!R(r);
}


void main() {
	import std.stdio;

	string s = "Amazing Stuff".toLower; // alias this!
	writeln(s);

	string[string] lol;
	lol["FOO"] = "FOO".toLower; // alias this!

	writeln(lol);
}

---


The code breakage is minimal (especially if we don't actually deprecate that eager method) - cases where a string is expected is automatically handled by the alias this, and pipelines using auto will just work. Copying this struct has the same semantics as copying the string The change of type can break code - but only code that was neither quite static nor quite generic.

Code that statically takes a string works, as will returning a string, that's also covered by alias this. Code that generically works on input/forward ranges works, as this is still a by-value forward range. Only code that takes a template argument and literally checks if(is(T == string)) or if(is(isArray!T)) and those variants will break on this.



I confess, that is some code, but with alias this, we have a migration path to change a lot of usages of the existing functions to be lazy without dreaming up new names.

Moreover, with this, some old code will *automatically* be upgraded to laziness without needing to change at all too. Tell me that doesn't at least tempt you!
June 24, 2015
On Wednesday, 24 June 2015 at 00:16:49 UTC, Tofu Ninja wrote:
> On Tuesday, 23 June 2015 at 23:58:52 UTC, Vladimir Panteleev wrote:
>> Another point: the range-ification of Phobos is only going to continue. This means that, should this scheme be followed, the number of functions with "Lazy" in the same is only going to grow, and as these functions are intended to become the canonical way to write modern D, so will the number of occurrences of "Lazy" in a typical canonical D program. I think this is a strong argument for avoiding "Lazy", at least for functions which intend to displace their eager counterparts.
>
> But now you are going to have to come up with a clever name for every replacement and the clarity of each will be shoty at best. The append lazy convention at least is a convention that is very clear, the other way has no rules, you just are making up new names.

Well, it's true, any chosen decision is going to be a compromise.

Appending "Lazy" is only easy because the work to come up with suitable names has already been done for the eager variants. Finding suitable names for the lazy variants would entail doing similar work, perhaps with a bit more effort to communicate that this version is not eager.

I'll collect some data tomorrow to see if it's possible to find a likeable convention for lazy function names. But even if this will fail and we'll have to settle for inconsistency, I think overall the situation will still be better than having "Lazy" sprinkled everywhere. It will also be consistent with the names so far (e.g. join/joiner) :)

June 24, 2015
FWIW, I'm cool with any of the proposed options, as long as it isn't what's in master right now. They all have their downsides, but I can live with any of them.
June 24, 2015
On Tuesday, 23 June 2015 at 23:49:45 UTC, Vladimir Panteleev wrote:
> On Tuesday, 23 June 2015 at 23:17:54 UTC, Meta wrote:
>> I really hate this naming scheme for functions that take lazy parameters. I still don't see why we don't do the (IMO) simplest and most intuitive thing and name them lazyToLower / lazyToUpper (or toLowerLazy / toUpperLazy). There is precedent with C#'s handling of async functions; for example, AccessTheWebAsync or GetStringAsync[1]. Your proposed naming scheme seems like it's trying to be too "clever" and really just ends up causing unnecessary confusion. This is not Ruby.
>> [1]https://msdn.microsoft.com/en-us/library/hh191443.aspx
>
> I'm not sure about this... I've seen another proposal for a "lazy" suffix in the other thread, but I think this won't be great in the long run:
>
> - Ultimately, we want to encourage use of the lazy versions, in the same way that e.g. std.algorithm and std.range are encouraged over eager operations for arrays.
>
> - There is no consistency with any existing naming schemes. Currently no names in Phobos contain the word "Lazy".

And hopefully not many would have to. I can't say that this is the right solution for all lazy / range-based code going forward, but it's better than what we have, and I believe it's better than withExtension / upperCased / etc.

> - If std.algorithm were to follow this convention, it would have lazyJoin instead of joiner, lazySplit instead of splitter, lazyConcat OSLT instead of chain, etc. Given a typical program using std.algorithm, do you think such names would look better there than the current ones?

They would definitely be more recognizable as lazy functions, at the least. This would make code using std.algorithm more verbose, but we're not looking at changing every name in std.algorithm. We're looking at changing a couple of very bad names that give no indication that they're lazy / range-based (and let's not forget that the two aren't synonymous; we do have a lazy keyword after all).

> - I'm not sure about the C# async analogy: with "async", the methods are used in a different way. The new range-based functions are used in the same way, but work on different types.
>
> Here's an example program using setExt[ension] and toLower[Case], in 4 variants...
>
> https://gist.github.com/CyberShadow/5cc7e926f566d56a672f
>
> IMHO, in this case, the "Lazy" suffix is a distracting technicality that doesn't carry its weight. Am I the only one?

It is a bit longer, but 4 extra characters is not all that much to pay to make a few functions much clearer about what they do.
June 24, 2015
On Tuesday, 23 June 2015 at 23:13:11 UTC, Mike wrote:
> `setExtensionLazy`
>
> Mike

I really don't like the Lazy suffix. Ignoring the issue of making things somewhat uglier solely for the purpose of ambiguity, it also leads to confusion regarding whether you should be invoking foo or fooLazy. Is there a fooLazy for this, or is it just foo, and why? Just because it was implemented before some arbitrary point? The lazy approach should be strongly preferred and should be the default; if the user wants the non-lazy version, they can use .array. Plus, as mentioned, people will start thinking that their own code should use this Lazy suffix which is likely something we don't want to encourage.

The current setExt name has the same issues I mentioned above, and it honestly is very odd to me to see setExt as well as setExtension if we're not intending to slowly phase out setExtension. The proposed withExtension indicates that it takes in a range and returns a range with the modifications applied, and I quite like it. I think that should be a trend for lazy algorithms, or at least a way to disambiguate.