digitalmars.D.learn - splitter string/char different behavior
- SrMordred (7/7) Sep 30 2017 writeln( "a.b.c".splitter('.').dropBack(1) ); //compiles ok
- Jon Degenhardt (16/23) Sep 30 2017 It's easy to overlook, but documentation for splitter starts out:
- WhatMeWorry (6/25) Sep 30 2017 Would it be correct to just update the documentation to say
- SrMordred (2/13) Sep 30 2017 But this works:
- Jon Degenhardt (3/18) Sep 30 2017 Geez, my mistake. I'm sorry about that. It's dropback that's
- Jon Degenhardt (9/16) Sep 30 2017 Let's try again. I'm not sure the full explanation, but likely
- Jonathan M Davis (17/37) Sep 30 2017 Well, figuring out where to split when iterating in reverse is trivial w...
- SrMordred (7/17) Sep 30 2017 Nice!
- Jonathan M Davis (9/27) Sep 30 2017 When the compiler can't find a matching overload for a templated functio...
writeln( "a.b.c".splitter('.').dropBack(1) ); //compiles ok writeln( "a.b.c".splitter(".").dropBack(1) ); //error: Error: template std.range.dropBack cannot deduce function from argument types !()(Result, int), candidates are: (...) Hm.. can someone explain whats going on?
Sep 30 2017
On Saturday, 30 September 2017 at 17:17:17 UTC, SrMordred wrote:writeln( "a.b.c".splitter('.').dropBack(1) ); //compiles ok writeln( "a.b.c".splitter(".").dropBack(1) ); //error: Error: template std.range.dropBack cannot deduce function from argument types !()(Result, int), candidates are: (...) Hm.. can someone explain whats going on?It's easy to overlook, but documentation for splitter starts out: Lazily splits a range using an element as a separator. An element of a string is a char, not a string. It needs to be read somewhat literally, but it is correct. It's also part of template constraint, useful once you've become accustomed to reading them: auto splitter(alias pred = "a == b", Range, Separator)(Range r, Separator s) if (is(typeof(binaryFun!pred(r.front, s)) : bool) && .... For "a.b.c"splitter(x), Range r is a string, r.front is a char. The template can only be instantiated if the predicate function is valid. The predicate function is "a == b". Since r.front is a char, then s must be a type that can be compared with '=='. A string and char cannot be compared with '==', which is why the a valid template instantiation could not be found.
Sep 30 2017
On Saturday, 30 September 2017 at 18:21:11 UTC, Jon Degenhardt wrote:On Saturday, 30 September 2017 at 17:17:17 UTC, SrMordred wrote:Would it be correct to just update the documentation to say "Lazily splits a range using an char as a separator" ? what is it; wchar and dchar too? I notice the example that is there has ' ' as the element.[...]It's easy to overlook, but documentation for splitter starts out: Lazily splits a range using an element as a separator. An element of a string is a char, not a string. It needs to be read somewhat literally, but it is correct. It's also part of template constraint, useful once you've become accustomed to reading them: auto splitter(alias pred = "a == b", Range, Separator)(Range r, Separator s) if (is(typeof(binaryFun!pred(r.front, s)) : bool) && .... For "a.b.c"splitter(x), Range r is a string, r.front is a char. The template can only be instantiated if the predicate function is valid. The predicate function is "a == b". Since r.front is a char, then s must be a type that can be compared with '=='. A string and char cannot be compared with '==', which is why the a valid template instantiation could not be found.
Sep 30 2017
But this works: writeln("a.b.c".splitter(".") );For "a.b.c"splitter(x), Range r is a string, r.front is a char. The template can only be instantiated if the predicate function is valid. The predicate function is "a == b". Since r.front is a char, then s must be a type that can be compared with '=='. A string and char cannot be compared with '==', which is why the a valid template instantiation could not be found.Would it be correct to just update the documentation to say "Lazily splits a range using an char as a separator" ? what is it; wchar and dchar too? I notice the example that is there has ' ' as the element.
Sep 30 2017
On Saturday, 30 September 2017 at 19:26:14 UTC, SrMordred wrote:Geez, my mistake. I'm sorry about that. It's dropback that's failing, not splitter.But this works: writeln("a.b.c".splitter(".") );For "a.b.c"splitter(x), Range r is a string, r.front is a char. The template can only be instantiated if the predicate function is valid. The predicate function is "a == b". Since r.front is a char, then s must be a type that can be compared with '=='. A string and char cannot be compared with '==', which is why the a valid template instantiation could not be found.Would it be correct to just update the documentation to say "Lazily splits a range using an char as a separator" ? what is it; wchar and dchar too? I notice the example that is there has ' ' as the element.
Sep 30 2017
On Saturday, 30 September 2017 at 17:17:17 UTC, SrMordred wrote:writeln( "a.b.c".splitter('.').dropBack(1) ); //compiles ok writeln( "a.b.c".splitter(".").dropBack(1) ); //error: Error: template std.range.dropBack cannot deduce function from argument types !()(Result, int), candidates are: (...) Hm.. can someone explain whats going on?Let's try again. I'm not sure the full explanation, but likely involves two separate template overloads being instantiated, each with a separate definition of the return type. * "a.b.c".splitter('.') - This overload: https://github.com/dlang/phobos/blob/master/std/algorithm/iteration.d#L3696-L3703 * "a.b.c".splitter(".") - This overload: https://github.com/dlang/phobos/blob/master/std/algorithm/iteration.d#L3973-L3982 But why one supports dropBack and the other doesn't I don't know.
Sep 30 2017
On Saturday, September 30, 2017 20:18:25 Jon Degenhardt via Digitalmars-d- learn wrote:On Saturday, 30 September 2017 at 17:17:17 UTC, SrMordred wrote:Well, figuring out where to split when iterating in reverse is trivial when splitting on a single element, but it's not when dealing with a range of elements. Sure, in this case, because the range happens to be only one character long, it would be easy, but as soon as it has multiple characters, it wouldn't be - especially if you got nonsense like auto result = "ttttttttttttt".splitter("ttt"); In order to know where to split, it really has to do it from the front. If it starts from the back, you won't necessarily split in the same places as when iterating from the front, and that would violate how bidirectional ranges are supposed to work (the elements should be the same - just in reverse - if you iterate from the back). That being the case, it makes sense that splitting on a single element would result in a range that was bidirectional, whereas splitting on a range of elements would result in a range that's only a forward range. - Jonathan M Daviswriteln( "a.b.c".splitter('.').dropBack(1) ); //compiles ok writeln( "a.b.c".splitter(".").dropBack(1) ); //error: Error: template std.range.dropBack cannot deduce function from argument types !()(Result, int), candidates are: (...) Hm.. can someone explain whats going on?Let's try again. I'm not sure the full explanation, but likely involves two separate template overloads being instantiated, each with a separate definition of the return type. * "a.b.c".splitter('.') - This overload: https://github.com/dlang/phobos/blob/master/std/algorithm/iteration.d#L369 6-L3703 * "a.b.c".splitter(".") - This overload: https://github.com/dlang/phobos/blob/master/std/algorithm/iteration.d#L397 3-L3982 But why one supports dropBack and the other doesn't I don't know.
Sep 30 2017
In order to know where to split, it really has to do it from the front. If it starts from the back, you won't necessarily split in the same places as when iterating from the front, and that would violate how bidirectional ranges are supposed to work (the elements should be the same - just in reverse - if you iterate from the back). That being the case, it makes sense that splitting on a single element would result in a range that was bidirectional, whereas splitting on a range of elements would result in a range that's only a forward range. - Jonathan M DavisNice! since dropBack is a BidirectionalRange everything make sense now. Thanks everybody! I just think that the error message should be a little better, since I have no idea about the incompatible Range types looking only to the error message. (Dont know if is possible, but anyway.. )
Sep 30 2017
On Sunday, October 01, 2017 00:56:23 SrMordred via Digitalmars-d-learn wrote:When the compiler can't find a matching overload for a templated function, look at its template constraint, since you either passed the wrong number of arguments, the wrong type of arguments, or the arguments you passed failed the template constraint. The template constraints aren't always as easy to read as would be nice (especially if there are several overloads), but the key information is there. - Jonathan M DavisIn order to know where to split, it really has to do it from the front. If it starts from the back, you won't necessarily split in the same places as when iterating from the front, and that would violate how bidirectional ranges are supposed to work (the elements should be the same - just in reverse - if you iterate from the back). That being the case, it makes sense that splitting on a single element would result in a range that was bidirectional, whereas splitting on a range of elements would result in a range that's only a forward range. - Jonathan M DavisNice! since dropBack is a BidirectionalRange everything make sense now. Thanks everybody! I just think that the error message should be a little better, since I have no idea about the incompatible Range types looking only to the error message. (Dont know if is possible, but anyway.. )
Sep 30 2017