Bug 11466 – std.range.zip is not nothrow

Status
RESOLVED
Resolution
WORKSFORME
Severity
normal
Priority
P2
Component
phobos
Product
D
Version
D2
Platform
x86
OS
Windows
Creation time
2013-11-07T03:22:29Z
Last change time
2019-12-19T11:10:14Z
Keywords
EH, rejects-valid
Assigned to
No Owner
Creator
bearophile_hugs

Comments

Comment #0 by bearophile_hugs — 2013-11-07T03:22:29Z
import std.range: zip; void main() nothrow { foreach (p; zip([10], [20])) {} } dmd 2.064 gives me: test.d(3): Error: 'std.range.Zip!(int[], int[]).Zip.empty' is not nothrow test.d(3): Error: 'std.range.Zip!(int[], int[]).Zip.popFront' is not nothrow test.d(2): Error: function 'D main' is nothrow yet may throw I think that zip should work in a nothrow function. - - - - - - - - - - - Another example of the same problem: import std.algorithm: reduce; import std.range: zip; void main() nothrow { reduce!((a, b) => 1)(1, zip([10], [20])); } dmd gives: test.d(4): Error: 'test.main.reduce!((a, b) => 1).reduce!(int, Zip!(int[], int[])).reduce' is not nothrow test.d(3): Error: function 'D main' is nothrow yet may throw - - - - - - - - - - - Another problem: import std.range: zip; void foo1(int[] data) @safe { foreach (pair; zip(data, data)) {} // OK } void foo2(in int[] data) @safe { foreach (pair; zip(data, data)) {} // Error } void main() {} dmd gives: test.d(6): Error: safe function 'test.foo2' cannot call system function 'std.range.Zip!(const(int)[], const(int)[]).Zip.front'
Comment #1 by bearophile_hugs — 2014-12-04T22:11:01Z
In dmd 2.067alpha this code compiles: import std.range: zip; void foo1(int[] data) @safe { foreach (pair; zip(data, data)) {} } void foo2(in int[] data) @safe { foreach (pair; zip(data, data)) {} } void main() {}
Comment #2 by hsteoh — 2014-12-04T22:12:15Z
So this bug can be closed?
Comment #3 by bearophile_hugs — 2014-12-04T22:25:12Z
(In reply to hsteoh from comment #2) > So this bug can be closed? No, it can't because this fails still: import std.range: zip; void main() nothrow { foreach (p; zip([10], [20])) {} }
Comment #4 by hsteoh — 2014-12-17T18:06:01Z
Zip.empty and Zip.popFront call enforce, which is not nothrow. This can't be eliminated because the runtime length of the ranges passed to zip() is not known, and zip() will throw an exception if unequal-length ranges are passed to it. I don't know how to resolve this, since the only way to make Zip nothrow is to change enforce to assert, but that means you'll get array bounds violations at runtime if the input arguments have unequal lengths.
Comment #5 by bearophile_hugs — 2014-12-17T19:23:35Z
(In reply to hsteoh from comment #4) > zip() will throw an exception if unequal-length ranges are passed to it. This is not true, this doesn't throw: void main() { import std.range: zip, StoppingPolicy; int[] a = [1]; int[] b = [1, 2]; foreach (pair; zip(a, b)) {} foreach (pair; zip(StoppingPolicy.shortest, a, b)) {} foreach (pair; zip(StoppingPolicy.longest, a, b)) {} } Only this one throws: void main() { import std.range: zip, StoppingPolicy; int[] a = [1]; int[] b = [1, 2]; foreach (pair; zip(StoppingPolicy.requireSameLength, a, b)) {} } > I don't know how to resolve this, The solution is to give StoppingPolicy as template argument to zip() instead of giving it as run-time value. This allows to specialize zip() at compile-time, allowing zip() with StoppingPolicy.shortest (that is the default) and with StoppingPolicy.longest to be nothrow. And leaving only the quite rarely used zip() with StoppingPolicy.requireSameLength not nothrow. For API compatibility you can even leave both ways to give StoppingPolicy to zip, or you can slowly deprecate the old way.
Comment #6 by hsteoh — 2014-12-17T19:42:24Z
Good idea. However, it will break compatibility with the current Zip struct, which unfortunately is public so some user code out there may be naming it directly. Looks like we'll have to introduce a different overload of Zip for the compile-time StoppingPolicy variant. Code duplication galore. :-(
Comment #7 by bugzilla — 2016-06-08T03:40:30Z
Since the @safe version compiles successfully, I'm going to remove the 'safe' keyword and @safe from the title.
Comment #8 by bugzilla — 2019-12-19T11:10:14Z
Fixed since 2.080.1