Thread overview | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
July 11, 2013 Difficulties with std.variant.Algebraic | ||||
---|---|---|---|---|
| ||||
I've been playing around with std.variant.Algebraic, trying to define a very simple option type. However, I've been running into quite a few problems. My implementation is as follows: import std.conv; import std.variant; struct Some(T) { T payload; alias payload this; } struct None { } struct Option(T) { Algebraic!(Some!T, None) payload; alias payload this; } Option!int unreliable(int val) { if (val == 0) { return None(); } else { return Some!int(val); } } Unfortunately, I can't return values of type Some or None from "unreliable" and expect the compiler to know that they should become an Algebraic wrapped in an Option. This is annoying, but I can't expect magic. Maybe if I'm explicit: Option!int unreliable(int val) { if (val == 0) { //Nope return cast(Option!int)None(); } else { //Nope return cast(Option!int)Some!int(val); } } Option!int unreliable(int val) { if (val == 0) { //Nope return cast(Option!int)None(); } else { //Nope return cast(Option!int)Some!int(val); } } Option!int unreliable(int val) { if (val == 0) { //Nope return cast(Algebraic!(Some!int, None))None(); } else { //Nope return cast(Algebraic!(Some!int, None))Some!int(val); } } Okay, I'll try constructing a fresh struct and returning that: Option!int unreliable(int val) { if (val == 0) { //Nope return Option!int(None()); } else { //Nope return Option!int(Some!int(val)); } } One final, last-ditch effort: Option!int unreliable(int val) { if (val == 0) { return Option!int(cast(Algebraic!(Some!int, None))None()); } else { return Option!int(cast(Algebraic!(Some!int, None))Some!int(val)); } } Yes! It worked. The only problem is that this is completely unacceptable to type. The only other solution I can think of would be to define constructors for Option that take a Some and a None. I suppose it's not *all* bad, though. I mean, it compiles... void main() { auto maybeNone = unreliable(10); //Error: template std.variant.visit cannot deduce template function from argument types !()(Option!(int)) assert(maybeNone.visit!((Some!int s) => text("Value is ", s), (None n) => "No value") == 10); } I don't know whether to laugh or cry. |
July 11, 2013 Re: Difficulties with std.variant.Algebraic | ||||
---|---|---|---|---|
| ||||
Posted in reply to Meta | On Thursday, 11 July 2013 at 03:06:39 UTC, Meta wrote:
> struct Option(T)
> {
> Algebraic!(Some!T, None) payload;
>
> alias payload this;
> }
This is untested but it probably looks something like this:
private alias MaybeType = Algebraic!(Some!T, None);
Option!int ans;
ans.payload = MaybeType(None);
|
July 11, 2013 Re: Difficulties with std.variant.Algebraic | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jesse Phillips | On Thursday, 11 July 2013 at 04:03:19 UTC, Jesse Phillips wrote:
> On Thursday, 11 July 2013 at 03:06:39 UTC, Meta wrote:
>> struct Option(T)
>> {
>> Algebraic!(Some!T, None) payload;
>>
>> alias payload this;
>> }
>
> This is untested but it probably looks something like this:
>
>
> private alias MaybeType = Algebraic!(Some!T, None);
>
> Option!int ans;
> ans.payload = MaybeType(None);
Ideally, payload would be private, and only exposed through alias this. It's somewhat unfortunate that this is necessary in the first place. D doesn't happen to have something like an opImplicitCast, does it?
|
July 11, 2013 Re: Difficulties with std.variant.Algebraic | ||||
---|---|---|---|---|
| ||||
Posted in reply to Meta | Meta:
> I don't know whether to laugh or cry.
Algebraic has several problems, but your code has other problems.
I suggest to take a look at Nullable, especially the version that makes a constant value the "null".
Also try to almost never use cast() in your code, unless you _really_ know what you are doing.
Expecting a bit of magic from the D compiler is OK. But someone has to ask for it in a clean way, someone has to implement it, and someone else has to accept it.
Ask if you need more help.
Bye,
bearophile
|
July 11, 2013 Re: Difficulties with std.variant.Algebraic | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | Some example code: import std.typecons; Nullable!int unreliable1(in int val) pure nothrow { if (val == 0) { return typeof(return)(); } else { return typeof(return)(val); } } Nullable!(int, 0) unreliable2(in int val) pure nothrow { if (val == 0) { return typeof(return)(); } else { return typeof(return)(val); } } void main() { auto nx1 = unreliable1(10); auto nx2 = unreliable2(10); } Bye, bearophile |
July 11, 2013 Re: Difficulties with std.variant.Algebraic | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | > Nullable!(int, 0) unreliable2(in int val) pure nothrow {
> if (val == 0) {
> return typeof(return)();
> } else {
> return typeof(return)(val);
> }
> }
Sorry, I meant:
import std.typecons;
Nullable!int unreliable1(in int val) pure nothrow {
if (val == 0) {
return typeof(return)();
} else {
return typeof(return)(val);
}
}
Nullable!(int, 0) unreliable2(in int val) pure nothrow {
return typeof(return)(val);
}
void main() {
auto nx1 = unreliable1(10);
auto nx2 = unreliable2(10);
}
Bye,
bearophile
|
July 11, 2013 Re: Difficulties with std.variant.Algebraic | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On Thursday, 11 July 2013 at 12:30:17 UTC, bearophile wrote: > Algebraic has several problems, but your code has other problems. Oh, no doubt. This isn't meant to be serious, industrial strength code. > I suggest to take a look at Nullable, especially the version that makes a constant value the "null". Nullable will work in this case, but it doesn't solve the general problem with Algebraic. > Also try to almost never use cast() in your code, unless you _really_ know what you are doing. I'm well aware of the dangers of cast. I was just playing around, trying to get this to work. > Expecting a bit of magic from the D compiler is OK. But someone has to ask for it in a clean way, someone has to implement it, and someone else has to accept it. Now that I think about it, I'm wondering exactly why the subtypes of Algebraic are not covariant with it when returned from a function. It works fine with other types that use alias this, e.g.: import std.variant; struct Test1 { } struct Test2 { Test1 t; alias t this; } Test1 covarReturn() { //Fine return Test2(); } |
July 11, 2013 Re: Difficulties with std.variant.Algebraic | ||||
---|---|---|---|---|
| ||||
Posted in reply to Meta | Meta:
> Nullable will work in this case, but it doesn't solve the general problem with Algebraic.
Then is this an acceptable solution?
import std.variant;
struct None {}
template Option(T) {
alias Option = Algebraic!(T, None);
}
Option!int unreliable(int val) pure nothrow {
if (val == 0) {
return typeof(return)(None());
} else {
return typeof(return)(val);
}
}
void main() {}
Bye,
bearophile
|
July 11, 2013 Re: Difficulties with std.variant.Algebraic | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On Thursday, 11 July 2013 at 16:48:00 UTC, bearophile wrote:
> Meta:
>
>> Nullable will work in this case, but it doesn't solve the general problem with Algebraic.
>
> Then is this an acceptable solution?
> ...
That is a bit better, yes. Still somewhat clunky, but workable. It'd still be nice if it wasn't necessary. Why does it break when I use Some!int instead of just a bare int?
|
July 11, 2013 Re: Difficulties with std.variant.Algebraic | ||||
---|---|---|---|---|
| ||||
Posted in reply to Meta | On Thursday, 11 July 2013 at 17:11:05 UTC, Meta wrote:
> On Thursday, 11 July 2013 at 16:48:00 UTC, bearophile wrote:
> That is a bit better, yes. Still somewhat clunky, but workable. It'd still be nice if it wasn't necessary. Why does it break when I use Some!int instead of just a bare int?
Oh, right, I see. I missed the change from "struct" to "template".
|
Copyright © 1999-2021 by the D Language Foundation