On Wednesday, 24 June 2015 at 01:04:01 UTC, Adam D. Ruppe wrote:
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!

Yup, mind completely blown.

I almost want to put "alias eager this;" in all my ranges now...

Reply via email to