www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - splitter, compilation issue

reply sigod <sigod.mail gmail.com> writes:
Here's simple code:

	import std.algorithm;
	import std.array;
	import std.file;
	
	void main(string[] args)
	{
		auto t = args[1].readText()
			.splitter('\n')
			.filter!(e => e.length)
			.split("---")
		;
	}

Looks like it should work, but it won't compile. DMD 2.068.2 
fails with this error:

	Error: template std.algorithm.iteration.splitter cannot deduce 
function from argument types !()(FilterResult!(__lambda2, 
Result), string), candidates are:
	...
	Error: template instance 
std.array.split!(FilterResult!(__lambda2, Result), string) error 
instantiating

It compiles if I insert `.array` before `.split(...`.

Am I missing something? Or it's a bug? I've tried to make a brief 
search in the bug tracker, but didn't found anything.

P.S. dpaste gives very strange error:

	/d712/f815.d(8): Error: unterminated character constant
	/d712/f815.d(9): Error: unterminated character constant
	... and so on
Oct 27 2015
next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 10/27/2015 01:58 PM, sigod wrote:
 Here's simple code:

      import std.algorithm;
      import std.array;
      import std.file;

      void main(string[] args)
      {
          auto t = args[1].readText()
              .splitter('\n')
              .filter!(e => e.length)
              .split("---")
          ;
      }

 Looks like it should work
split's documentation says that it requires a ForwardRange but the output of filter is an InputRange. (I can't imagine now why split has that requirement.) Ali
Oct 27 2015
next sibling parent sigod <sigod.mail gmail.com> writes:
On Tuesday, 27 October 2015 at 21:45:10 UTC, Ali Çehreli wrote:
 On 10/27/2015 01:58 PM, sigod wrote:
 Here's simple code:

      import std.algorithm;
      import std.array;
      import std.file;

      void main(string[] args)
      {
          auto t = args[1].readText()
              .splitter('\n')
              .filter!(e => e.length)
              .split("---")
          ;
      }

 Looks like it should work
split's documentation says that it requires a ForwardRange but the output of filter is an InputRange. (I can't imagine now why split has that requirement.) Ali
It still doesn't work. src\phobos\std\array.d(1562): Error: template std.algorithm.iteration.splitter cannot deduce function from argument types !()(Result, string) Sorry, I should've simplified example more.
Oct 27 2015
prev sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Tuesday, 27 October 2015 at 21:45:10 UTC, Ali Çehreli wrote:
 split's documentation says that it requires a ForwardRange but 
 the output of filter is an InputRange. (I can't imagine now why 
 split has that requirement.)
You need to .save at the beginning so when you hit the split point, it can present the whole string as front. You don't know if you've hit the split point until after you've done a fair amount of popFront calls, so if you haven't saved it before, it is impossible to return the first element before the splitter string.
Oct 27 2015
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 10/27/2015 02:55 PM, Adam D. Ruppe wrote:
 On Tuesday, 27 October 2015 at 21:45:10 UTC, Ali Çehreli wrote:
 split's documentation says that it requires a ForwardRange but the
 output of filter is an InputRange. (I can't imagine now why split has
 that requirement.)
You need to .save at the beginning so when you hit the split point, it can present the whole string as front. You don't know if you've hit the split point until after you've done a fair amount of popFront calls, so if you haven't saved it before, it is impossible to return the first element before the splitter string.
I knew that! :p Ali
Oct 27 2015
prev sibling next sibling parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Tuesday, October 27, 2015 20:58:56 sigod via Digitalmars-d-learn wrote:
 Here's simple code:

   import std.algorithm;
   import std.array;
   import std.file;

   void main(string[] args)
   {
       auto t = args[1].readText()
           .splitter('\n')
           .filter!(e => e.length)
           .split("---")
       ;
   }

 Looks like it should work, but it won't compile. DMD 2.068.2
 fails with this error:

   Error: template std.algorithm.iteration.splitter cannot deduce
 function from argument types !()(FilterResult!(__lambda2,
 Result), string), candidates are:
   ...
   Error: template instance
 std.array.split!(FilterResult!(__lambda2, Result), string) error
 instantiating

 It compiles if I insert `.array` before `.split(...`.

 Am I missing something? Or it's a bug? I've tried to make a brief
 search in the bug tracker, but didn't found anything.

 P.S. dpaste gives very strange error:

   /d712/f815.d(8): Error: unterminated character constant
   /d712/f815.d(9): Error: unterminated character constant
   ... and so on
Well, split calls splitter, and it doesn't make much of an attempt to check its arguments in its template constraint, mostly passing the buck onto splitter, since it's really just a wrapper around splitter that calls array on the result. You could actually reduce your code down to something more like auto t = "hello".filter!"true"().splitter(" "); and you'd have the same problem. And looking at splitter's template constraint, it requires either a narrow string (which the result of filter is not) or a range for which hasSlicing is true (which is not the case for the result of filter). Whether splitter could be implemented without that (e.g. returning a range of Take), I don't know, but it's pretty clear that the current implementation requires slicing, and if you're using filter, that means that you'd need to do something like use array to convert it to a range which _can_ be sliced to pass to split or splitter. - Jonathan M Davis
Oct 27 2015
parent sigod <sigod.mail gmail.com> writes:
On Tuesday, 27 October 2015 at 21:54:33 UTC, Jonathan M Davis 
wrote:
 Well, split calls splitter, and it doesn't make much of an 
 attempt to check its arguments in its template constraint, 
 mostly passing the buck onto splitter, since it's really just a 
 wrapper around splitter that calls array on the result.
Looks like one more way to improve documentation.
Oct 27 2015
prev sibling parent reply sigod <sigod.mail gmail.com> writes:
Well, problem boils down to `splitter` having a greater 
constraints than most functions can meet.

Thanks everyone for clarification.

P.S. Maybe I should repost my question on SO? I really thought it 
was a bug, so I posted it here.
Oct 27 2015
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Tuesday, 27 October 2015 at 22:18:55 UTC, sigod wrote:
 P.S. Maybe I should repost my question on SO? I really thought 
 it was a bug, so I posted it here.
You could, but I'd say the same thing there - it is no bug, the algorithm legitimately needs that functionality to split successfully. At the same time, filter legitimately needs to /drop/ that functionality to work efficiently. So the error kinda sucks (maybe i should write this as a tip, whenever you see that pattern, adding a .array can work around it), but it isn't a bug. The reason splitter doesn't try to automatically buffer or something like that is that std.algorithm tries to be as low cost as possible in all cases, and asks you to be aware of and pay the cost when it needs to occur. So if it needs a buffer and can't get one for free, it fails to compile, so you are aware of the problem and can provide one that works best for you (or just stick in .array somewhere to do an easy, generic solution)
Oct 27 2015
parent reply sigod <sigod.mail gmail.com> writes:
On Tuesday, 27 October 2015 at 22:33:32 UTC, Adam D. Ruppe wrote:
 On Tuesday, 27 October 2015 at 22:18:55 UTC, sigod wrote:
 P.S. Maybe I should repost my question on SO? I really thought 
 it was a bug, so I posted it here.
You could, but I'd say the same thing there
I don't expect different answer there. Main idea is to increase language presence and therefore popularity. I saw someone (I think it was Martin Nowak) somewhere saying that maybe we should move questions from Learn forum to SO.
 or just stick in .array somewhere to do an easy, generic 
 solution
Which completely works in this case. Since I'm writing just a code generation tool, which I'll need to use just a few times.
Oct 27 2015
parent reply sigod <sigod.mail gmail.com> writes:
On Tuesday, 27 October 2015 at 22:56:07 UTC, sigod wrote:
 On Tuesday, 27 October 2015 at 22:33:32 UTC, Adam D. Ruppe 
 wrote:
 On Tuesday, 27 October 2015 at 22:18:55 UTC, sigod wrote:
 P.S. Maybe I should repost my question on SO? I really 
 thought it was a bug, so I posted it here.
You could, but I'd say the same thing there
I don't expect different answer there. Main idea is to increase language presence and therefore popularity. I saw someone (I think it was Martin Nowak) somewhere saying that maybe we should move questions from Learn forum to SO.
 or just stick in .array somewhere to do an easy, generic 
 solution
Which completely works in this case. Since I'm writing just a code generation tool, which I'll need to use just a few times.
Posted it here: http://stackoverflow.com/q/33380674/944911 Only removed `filter` from code.
Oct 27 2015
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 28 October 2015 at 00:07:23 UTC, sigod wrote:
 Only removed `filter` from code.
You know, I was just writing an answer for this and I kinda changed my mind. Without filter... I think splitter.splitter ought to work. The implementation requires slicing unless you pass it a predicate. Only that overload works on minimal forward ranges. This compiles: import std.algorithm; import std.array; import std.stdio; void main(string[] args) { auto t = "foo\nbar\ncool---beans" .splitter('\n') .filter!(e => e.length) .splitter!(a => a == "bar") ; writeln(t); } It returns [["foo"], ["cool---beans"]]; it split it on the "bar" line in the middle. I think that might be basically what you want.
Oct 27 2015