How to implement filterMap

Siarhei Siamashka siarhei.siamashka at gmail.com
Sun Dec 31 09:47:27 UTC 2023


On Saturday, 30 December 2023 at 13:25:00 UTC, Christian Köstlin 
wrote:
> On Saturday, 30 December 2023 at 01:22:31 UTC, Siarhei 
> Siamashka wrote:
>> On Friday, 29 December 2023 at 23:10:47 UTC, Christian Köstlin 
>> wrote:
>>> Is there a way to implement filterMap (meaning do mapping of 
>>> a range, but if something happens during the map, leave this 
>>> element out of the resulting range).
>>
>> It's probably not a good idea to do this in general. Expecting 
>> a lot of exceptions handling happening during normal program 
>> execution (if you want to filter out roughly half of the input 
>> array) will result in a major performance loss. Exceptions are 
>> best left to just do error handling on a very rarely used code 
>> path for troubleshooting purposes.
>
> Thanks for the feedback.
>
> This might be true, but in my example I would parse the input 
> always with conv.to, so I would need to handle the exception(s).

I still think that a much better design is to have a try/catch 
block much higher in the call stack and print a "malformed input" 
error message to the user. Or handle the error in some other way 
(for example, allow the user to try again with a different input 
data).

> The "original" 
> https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter_map works with the Option(Some/None) ...

Here's an example with `Nullable`, inspired by the earlier 
comment from Alexandru Ermicioi:

```D
import std;
auto toNullableInt(string s) {
   try { return s.to!int.nullable; } catch (Exception e) {}
   Nullable!int ret;
   return ret;
}
void main() {
   // prints [2, 4]
   auto a = ["1", "2", "abc", ""];
   a.map!toNullableInt.filter!"!a.isNull".map!"a.get * 2".writeln;

   // prints [2, 4, 198]
   auto b = ["1", "2", "abc", "", "99999999999999999999", "99"];
   b.map!toNullableInt.filter!"!a.isNull".map!"a.get * 2".writeln;

   // prints [2, 4, -294967298, 198]
   auto c = ["1", "2", "abc", "", "1999999999", "99"];
   c.map!toNullableInt.filter!"!a.isNull".map!"a.get * 2".writeln;
}
```

Take a look at the `b` array. With this particular design, the 
"99999999999999999999" value is going to be silently filtered 
out. If you or your users happen to expect only non-digit string 
literals or empty strings to be filtered out, then there may be a 
very nasty and difficult to debug unexpected surprise awaiting 
down the road.

Also take a look at the `c` array. The handling of arithmetic 
overflows is a safety problem of the D language design. Certain 
types of input may cause overflows, which result in producing 
bogus data as a result of running your program and are very 
difficult to troubleshoot. The use of the GDC's `-ftrapv` option 
surely helps in troubleshooting such cases, but some software or 
D libraries may intentionally rely on the D's arithmetic 
wraparound feature.


More information about the Digitalmars-d-learn mailing list