digitalmars.D - Goofy code means opportunities in language design
- Andrei Alexandrescu (69/69) Sep 17 2020 Making a pass through Phobos code is very instructive. I find all kinds
- Timon Gehr (2/9) Sep 17 2020 https://issues.dlang.org/show_bug.cgi?id=16123
- Andrei Alexandrescu (2/12) Sep 17 2020 Thanks!
- Avrina (7/19) Sep 17 2020 This does something different. It returns the source range, and
- Stefan Koch (3/7) Sep 17 2020 Yep. type functions try to address one instance of those issues.
- Jacob Carlborg (4/88) Sep 18 2020 Isn't all this easily solved with opDispatch or `alias this`?
Making a pass through Phobos code is very instructive. I find all kinds of goofy code that really means the language doesn't allow people to do what they want to do. So they need to write all sorts of oddities. Consider this (from std.algorithm.iteration.cache): private struct _Cache(R, bool bidir) { ... private R source; static if (isInfinite!R) enum empty = false; else bool empty() property { return source.empty; } ... } These lines appear over and over in Phobos in ranges that simply want to "expose source.empty to clients of this type". There should be a mechanism for that, such as: alias empty = source.empty; So then whatever source.empty implements would be automatically present in _Cache. Now look at this beauty: static if (hasSlicing!R) { enum hasEndSlicing = is(typeof(source[size_t.max .. $])); static if (hasEndSlicing) { private static struct DollarToken{} enum opDollar = DollarToken.init; auto opSlice(size_t low, DollarToken) { return typeof(this)(source[low .. $]); } } static if (!isInfinite!R) { typeof(this) opSlice(size_t low, size_t high) { return typeof(this)(source[low .. high]); } } else static if (hasEndSlicing) { auto opSlice(size_t low, size_t high) in { assert(low <= high, "Bounds error when slicing cache."); } do { import std.range : takeExactly; return this[low .. $].takeExactly(high - low); } } } Oh boy. That's a really awkward way to say, "do slicing exactly like source does". Should be something like: static if (hasSlicing!R) { static if (hasMember!(R, "opDollar")) alias opDollar = source.opDollar; alias opSlice = source.opSlice; } Even better, as it seems common to say "forward if this other guy implements it: try alias opDollar = source.opDollar; try alias opSlice = source.opSlice;
Sep 17 2020
On 17.09.20 16:10, Andrei Alexandrescu wrote:These lines appear over and over in Phobos in ranges that simply want to "expose source.empty to clients of this type". There should be a mechanism for that, such as: alias empty = source.empty;https://issues.dlang.org/show_bug.cgi?id=16123
Sep 17 2020
On 9/17/20 10:29 AM, Timon Gehr wrote:On 17.09.20 16:10, Andrei Alexandrescu wrote:Thanks!These lines appear over and over in Phobos in ranges that simply want to "expose source.empty to clients of this type". There should be a mechanism for that, such as: alias empty = source.empty;https://issues.dlang.org/show_bug.cgi?id=16123
Sep 17 2020
On Thursday, 17 September 2020 at 14:10:58 UTC, Andrei Alexandrescu wrote:Oh boy. That's a really awkward way to say, "do slicing exactly like source does". Should be something like: static if (hasSlicing!R) { static if (hasMember!(R, "opDollar")) alias opDollar = source.opDollar; alias opSlice = source.opSlice; }This does something different. It returns the source range, and not the encapsulating range (Cache in this case).Even better, as it seems common to say "forward if this other guy implements it: try alias opDollar = source.opDollar; try alias opSlice = source.opSlice;Same problem as above. Also don't like "try" here, though it may fit with the english definition, it doesn't fit with D's use with exceptions. Don't want a situation like `static` with C.
Sep 17 2020
On Thursday, 17 September 2020 at 14:10:58 UTC, Andrei Alexandrescu wrote:Making a pass through Phobos code is very instructive. I find all kinds of goofy code that really means the language doesn't allow people to do what they want to do. So they need to write all sorts of oddities.Yep. type functions try to address one instance of those issues.
Sep 17 2020
On 2020-09-17 16:10, Andrei Alexandrescu wrote:Making a pass through Phobos code is very instructive. I find all kinds of goofy code that really means the language doesn't allow people to do what they want to do. So they need to write all sorts of oddities. Consider this (from std.algorithm.iteration.cache): private struct _Cache(R, bool bidir) { ... private R source; static if (isInfinite!R) enum empty = false; else bool empty() property { return source.empty; } ... } These lines appear over and over in Phobos in ranges that simply want to "expose source.empty to clients of this type". There should be a mechanism for that, such as: alias empty = source.empty; So then whatever source.empty implements would be automatically present in _Cache. Now look at this beauty: static if (hasSlicing!R) { enum hasEndSlicing = is(typeof(source[size_t.max .. $])); static if (hasEndSlicing) { private static struct DollarToken{} enum opDollar = DollarToken.init; auto opSlice(size_t low, DollarToken) { return typeof(this)(source[low .. $]); } } static if (!isInfinite!R) { typeof(this) opSlice(size_t low, size_t high) { return typeof(this)(source[low .. high]); } } else static if (hasEndSlicing) { auto opSlice(size_t low, size_t high) in { assert(low <= high, "Bounds error when slicing cache."); } do { import std.range : takeExactly; return this[low .. $].takeExactly(high - low); } } } Oh boy. That's a really awkward way to say, "do slicing exactly like source does". Should be something like: static if (hasSlicing!R) { static if (hasMember!(R, "opDollar")) alias opDollar = source.opDollar; alias opSlice = source.opSlice; } Even better, as it seems common to say "forward if this other guy implements it: try alias opDollar = source.opDollar; try alias opSlice = source.opSlice;Isn't all this easily solved with opDispatch or `alias this`? -- /Jacob Carlborg
Sep 18 2020