-
-
Notifications
You must be signed in to change notification settings - Fork 707
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: Add non-throwing variants of parse() and to() #6665
Conversation
Thanks for your pull request and interest in making D better, @nordlow! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please see CONTRIBUTING.md for more information. If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment. Bugzilla referencesYour PR doesn't reference any Bugzilla issue. If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog. Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub fetch digger
dub run digger -- build "master + phobos#6665" |
31b89a8
to
7c57fa1
Compare
I like the idea (and I'm generally in favor of using more
|
Sounds good to me. Two key questions:
I'll have a go at your proposal anyway... :) Update: Changed to using |
Yes and even Lines 3807 to 3823 in bb769cf
See also: https://dlang.org/changelog/2.080.0.html#std-typecons-nullable-apply That's because |
Ok, I'm all in on using |
I don’t think we should use Nullable, instead implement a proper Optional type. I have an implementation here [1] that implements the range interface and safe access. [1] https://github.com/jacob-carlborg/dlp/blob/master/source/dlp/core/optional.d |
Can you please describe why we need an Optional instead of a Nullable? Are there any other reasons than the above mentioned? |
No, it's mostly because it has a range interface and safe access interface. I also think it's a better, more descriptive name. |
How the is the interface AFAICT, This bug can at least be avoided if we instead use I agree that |
We already have |
I didn't say class Bar { int a; }
class Foo { Bar bar; }
auto foo = none!Foo;
auto a = foo.bar.a; // safe access, "a" will be an optional int
auto b = a.or(3); // unwraps "a" if it has a value, otherwise returns 3
auto c = a.map!(i => i * 4); // it also supports the range interface If the standard algorithms are used, the lambda will only be called if the optional has a value. When using |
So lets try adding your |
How about until we all settle on the return type, we simply use |
Another option would be add these functions first to |
Please no. I suggest we deprecate |
I agree An optional is explicit in intent and it'd be a much nicer interface with an Optional. Also, once we start using So super big +1 for putting this in std.experimental until we have an Optional type. |
Yes, I agree. I meant |
I've added a very basic version of |
I can't seem to add comments to an ordinary file. Could you open a mini-PR and link it here? edit: At a glance, you probably want to use the edit: edit: It seems to me there is little reason for this to not be a replacement for |
I can't say that I agree with that. Given that |
The logic of using ranges is, I think, that a type which may either contain one value or no value, ie. Nullable, is sort of a special case of a type which may contain any number of values, ie. ranges. Also possibly to gain a little of the generality of functional languages with their ability to write algorithms that apply to any arbitrary wrapper/container type, ie. monads. edit: The logic of not using |
|
Is it ok to add |
It would be better to have a separate PR. Would it make sense to build a new Optional type as well and have it be based on each other? |
Maybe edit: Ah, the flexibility of |
Honestly, the way Now, having a type that either holds a value or hold some sort of error type as proposed here is something different, but in its case, it basically holds a value regardless. It's just that it could be the target type or the error type.
Using std.variant does tend to cause subtle problems, but |
This runs into the problems that I've recently fixed in Nullable (by using a The Turducken post and the edit: Note that the struct part of the wrapper may not be necessary, since I misunderstood how unions work. Try it out! edit: Yes, it is necessary, since moveEmplace refuses to emplace into an immutable variable otherwise. edit: After looking at |
A union seems like a pretty good approach to back an Expected type - here's a dirty proof of concept based on SumType by @pbackus.
While you can treat a pointer the same sometime, it becomes conventional and not enforceable. |
I'm working on a fleshed-out version of |
Just a note - returning either Nulltable or Optional from parsing functions makes it impossible to distinguish the cause of error when there could be more than one (e.g. end of stream vs. overflow). With Expected the result contains arbitrarily rich information in case of failure. |
Is Expected different from Result? |
Result is usually
whereas expected is more like
|
Personally I would recommend against using the name "expected". The most common names for this type in functional-programming languages are "result" and "either". |
One issue with
Wrt names I find |
How does
? |
@nordlow I just meant it limits the error to one type. I think it would be better (without adding other types to Result) to allow not only allocated exceptions but lambdas that throw exceptions and strings from which exceptions can be constructed. In brief: |
@andralex If we want to store information from which an exception can be constructed, rather than an actual alias ExceptionArgs = Tuple!(string, "msg", string, "file", size_t, "line");
Result!(T, ExceptionArgs) fun(...)
{
// ...
if (ok)
return typeof(return)(T(...));
else
return typeof(return)(ExceptionArgs("no good", __FILE__, __LINE__));
} There's plenty of room for polish here, of course, but the basic approach ought to work. |
@pbackus understood, though exposing the arguments all the way to the user-facing API is not really nice (what if you change them later etc). Users should have a simple mechanism to get some uniform |
Note that SIL's |
This sounds like a mechanism-vs-policy issue. Certainly it would be ideal if we could live in a world where all functions reported errors in some uniform way, and it might be a good idea to adopt such a policy for Phobos, but we do not live in such a world, and I do not think that a general-purpose |
This idea would be better pursued as a low-level API design for Phobos 3. |
Putting it out in the open just to get early feedback.
See also: https://forum.dlang.org/post/hotgouygobclmesixayw@forum.dlang.org