Thread overview
Continue iteration after exception
Jan 23, 2013
Josh
Jan 23, 2013
bearophile
Jan 23, 2013
Josh
Jan 23, 2013
monarch_dodra
Jan 23, 2013
H. S. Teoh
Jan 23, 2013
monarch_dodra
Jan 23, 2013
Dmitry Olshansky
January 23, 2013
DMD 2.060, Windows 7 64-bit

Source:

import std.file;
import std.stdio;

void main()
{
    foreach (DirEntry d; dirEntries("C:\\", SpanMode.breadth))
        writeln(d.name);
}

This code stops with "std.file.FileException@std\file.d(2434): C:\Documents and Settings: Access is denied." when it gets to C:\Documents and Settings. On Windows 7 that doesn't actually exist, which is fine. What I'd like it to do is tell me that it doesn't exist, but continue iterating anyway. I've tried try-catch, but that just stops the iteration.

Any help is appreciated. Thanks :)

Josh
January 23, 2013
Josh:

> Any help is appreciated. Thanks :)

A possible solution: desugar the foreach range iteration protocol of dirEntries and wrap the relevant method with a try-catch.

Bye,
bearophile
January 23, 2013
On Wednesday, 23 January 2013 at 15:00:16 UTC, bearophile wrote:
> A possible solution: desugar the foreach range iteration protocol of dirEntries and wrap the relevant method with a try-catch.

Sorry, could you explain that a little? I'm not sure what desugar means :/
January 23, 2013
On Wednesday, 23 January 2013 at 15:24:02 UTC, Josh wrote:
> On Wednesday, 23 January 2013 at 15:00:16 UTC, bearophile wrote:
>> A possible solution: desugar the foreach range iteration protocol of dirEntries and wrap the relevant method with a try-catch.
>
> Sorry, could you explain that a little? I'm not sure what desugar means :/

He means you turn it into a normal loop with !empty, front and popFront.

That wouldn't really work anyways. Why you'd be able to catch the exception when calling popFront, and preserve your iteration state, you'd be unable to iterate past the exception point :/
January 23, 2013
On Wed, Jan 23, 2013 at 04:52:25PM +0100, monarch_dodra wrote:
> On Wednesday, 23 January 2013 at 15:24:02 UTC, Josh wrote:
> >On Wednesday, 23 January 2013 at 15:00:16 UTC, bearophile wrote:
> >>A possible solution: desugar the foreach range iteration protocol of dirEntries and wrap the relevant method with a try-catch.
> >
> >Sorry, could you explain that a little? I'm not sure what desugar means :/
> 
> He means you turn it into a normal loop with !empty, front and popFront.

This may not be possible if DirEntries is implemented with opApply instead of a range.

Anyway, since I don't think everyone is aware of what opApply is or what a range is, here's a (very) brief explanation:

In D, foreach loops can work with any user-defined type as long as they either (1) provide a method called "opApply", or (2) implement a range interface, that is, the methods "empty", "front", and "popFront".

The method opApply looks like this:

	int opApply(scope int delegate(X...) dg) { ... }

where X... represents the loop counter(s). For instance, if you want to
support:

	foreach (int x, int y; obj) { ... }

then opApply should look like:

	int opApply(scope int delegate(ref int x, ref int y) dg) { ... }

The idea is that opApply will iterate over the contents of the object and call the delegate dg with each value (or set of values).

Alternatively, the object can implement the range interface, which will also allow it to be used with std.algorithm and a whole bunch of other cool stuff. The minimal range interface requires the object to define the following methods:

	@property bool empty() {...} // return true if there are no more elements
	@property T front() {...} // return the current element
	void popFront() {...} // move to the next element

The compiler then translates ("lowers") a loop like:

	foreach (x; obj) { do_something(x); }

into:

	while (!obj.empty) {
		do_something(obj.front);
		obj.popFront();
	}

Hope this is helpful.


> That wouldn't really work anyways. Why you'd be able to catch the exception when calling popFront, and preserve your iteration state, you'd be unable to iterate past the exception point :/

Yeah, I think we might need an enhancement request to add a flag to ignore access errors while traversing the filesystem.


T

-- 
Latin's a dead language, as dead as can be; it killed off all the Romans, and now it's killing me! -- Schoolboy
January 23, 2013
On Wednesday, 23 January 2013 at 16:10:57 UTC, H. S. Teoh wrote:
> On Wed, Jan 23, 2013 at 04:52:25PM +0100, monarch_dodra wrote:
>> On Wednesday, 23 January 2013 at 15:24:02 UTC, Josh wrote:
>> >On Wednesday, 23 January 2013 at 15:00:16 UTC, bearophile wrote:
>> >>A possible solution: desugar the foreach range iteration
>> >>protocol of dirEntries and wrap the relevant method with a
>> >>try-catch.
>> >
>> >Sorry, could you explain that a little? I'm not sure what desugar
>> >means :/
>> 
>> He means you turn it into a normal loop with !empty, front and
>> popFront.
>
> [SNIP]
>
>> That wouldn't really work anyways. Why you'd be able to catch the
>> exception when calling popFront, and preserve your iteration state,
>> you'd be unable to iterate past the exception point :/
>
> Yeah, I think we might need an enhancement request to add a flag to
> ignore access errors while traversing the filesystem.
>
>
> T

As a workaround, one can manually and recursively iterate the files with a "shallow" span. The result would be a depth first iteration.

//----
void foo(string s)
{
    writeln(s);
    if (!s.isDir()) return;
    try
    {
        foreach(string dir; dirEntries(s, SpanMode.shallow))
        {
            foo(dir);
        }
    }
    catch {}
}

void main()
{
    foo(`C:\\`);
}
//----
January 23, 2013
23-Jan-2013 20:09, H. S. Teoh пишет:
> On Wed, Jan 23, 2013 at 04:52:25PM +0100, monarch_dodra wrote:
>> On Wednesday, 23 January 2013 at 15:24:02 UTC, Josh wrote:
>>> On Wednesday, 23 January 2013 at 15:00:16 UTC, bearophile wrote:
>>>> A possible solution: desugar the foreach range iteration
>>>> protocol of dirEntries and wrap the relevant method with a
>>>> try-catch.
>>>
>>> Sorry, could you explain that a little? I'm not sure what desugar
>>> means :/
>>
>> He means you turn it into a normal loop with !empty, front and
>> popFront.
>
> This may not be possible if DirEntries is implemented with opApply
> instead of a range.

It's a range.

TL;DR :)

-- 
Dmitry Olshansky