Bug 9086 – std.typecons.appendIfNotNull() or a better idea

Status
RESOLVED
Resolution
WORKSFORME
Severity
enhancement
Priority
P2
Component
phobos
Product
D
Version
D2
Platform
All
OS
All
Creation time
2012-11-27T18:21:00Z
Last change time
2017-07-02T14:43:52Z
Assigned to
nobody
Creator
bearophile_hugs

Comments

Comment #0 by bearophile_hugs — 2012-11-27T18:21:31Z
A problem with std.typecons.Nullable is that the D type system is not powerful enough to see this is correct code: import std.typecons; void main() nothrow { alias Nothing = Nullable!int; Nothing[] items; foreach (i; 0 .. 10) items ~= (i % 2) ? Nothing(i) : Nothing(); int[] result; foreach (x; items) if (!x.isNull) result ~= x.get; // Error: x.get is not nothrow } Another problem is that "x.get" verifies the enforcement even in the "then" clause, this is wasted computation, because x was tested already. One common enough use case for Nullable is to create arrays of Nullables and then filter out the null values. Currently code like this can't be nothrow: items.filter!(x => !x.isNull)().map!(x => x.get)() So I have created a little function named appendIfNotNull() that is nothrow: import std.typecons; void appendIfNotNull(T)(ref T[] items, Nullable!T x) pure nothrow { try { if (!x.isNull) items ~= x.get; } catch (Exception e) // enforce() exception. assert(0); } // Demo code -------------------------- import std.stdio, std.algorithm; alias Nothing = Nullable!int; Nothing[] foo(int n) nothrow { typeof(return) result; foreach (i; n .. n + 6) result ~= (i % 2) ? Nothing(i) : Nothing(); return result; } int[] bar() nothrow { typeof(return) numbers; foreach (i; 0 .. 3) foreach (x; foo(i * 10)) numbers.appendIfNotNull(x); return numbers; } void main() { writeln(bar()); foo(1).filter!(x => !x.isNull)().map!(x => x.get)().writeln(); } appendIfNotNull() is nothrow, but it wastes efficiency. So here is a simpler and more efficient implementation for the std.typecons module (because _isNull and _value fields are private): void appendIfNotNull(T)(ref T[] items, Nullable!T x) nothrow { if (!x._isNull) items ~= x._value; } Improvements for appendIfNotNull: - items instead of a T[] should be a range that supports appending. - x should be allowed to be one of both types of Nullables. appendIfNotNull() is not a very generic function, something better can be invented, usable in more cases. More general ideas are welcome.
Comment #1 by bearophile_hugs — 2012-12-18T14:11:54Z
See also here for some usage patterns of the Scala Option type: http://blog.tmorris.net/scalaoption-cheat-sheet/
Comment #2 by bearophile_hugs — 2013-12-10T12:07:23Z
A comment by Max Klyga: > Actually for Option there is no need for special casing as it acts as > an input range of one or zero elements, so all map/filter/etc. will > just work
Comment #3 by astrothayne — 2016-03-16T04:30:45Z
One way to deal with this could be to add an Option/Maybe type, or define a function get a range from a Nullable (or add some sort map and flatmap functions) (see http://forum.dlang.org/thread/[email protected]).
Comment #4 by dlang-bugzilla — 2017-07-02T14:43:52Z
(In reply to bearophile_hugs from comment #0) > A problem with std.typecons.Nullable is that the D type system is not > powerful enough to see this is correct code: This example now compiles fine. Fixed in https://github.com/dlang/phobos/pull/1103