February 03, 2014 Re: Templates: generic "return null;" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dicebot | On Monday, 3 February 2014 at 14:21:29 UTC, Dicebot wrote:
> On Monday, 3 February 2014 at 14:17:11 UTC, Chris wrote:
>> Probably. I tried using Nullable, but it caused some problems when the attribute wasn't defined:
>>
>> core.exception.AssertError@/usr/include/dmd/phobos/std/typecons.d(1233): Called `get' on null Nullable!int.
>
> This is intended. The very point of Nullable is to force you to handle `null` state before accessing actual payload.
Aha, I see. So in my scenario it is useless.
|
February 03, 2014 Re: Templates: generic "return null;" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dicebot | On Monday, 3 February 2014 at 14:21:29 UTC, Dicebot wrote:
> This is intended. The very point of Nullable is to force you to handle `null` state before accessing actual payload.
P.S. for this very reason in my own implementation of Optional I provide only delegate access method:
value.get(
() => { /* handle 'empty' case */ },
value => { /* 'value' is legit data */ }
);
|
February 04, 2014 Re: Templates: generic "return null;" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chris | On Monday, 3 February 2014 at 10:25:19 UTC, Chris wrote: > Is there a way I can make the return type in getAttribute generic? null does not work with numbers. > > MyStruct(T) { > T[T] attributes; > // .... > public auto getAttribute(T attr) { > if (!(attr in attributes)) { > return null; // Doesn't work for numbers! > } > return attributes[attr]; > } > } > > void main() { > auto myStr = MyStruct!int(0); // Error > } Whenever i am faced with this situation i do one (or more then one) of the following things. struct MyStruct(T) { T[T] attributes; //(1) Forward the underlying access method Eg: auto opBinaryRight(string s : "in")(T attrib) { return attrib in attributes; } //(2) make a try method. bool tryAttrib(T attrib, out T outAttrib) { auto p = attrib in attributes; if(p) outAttrib = *p; return p !is null; } //(3) Give user option to set default value. T attribOrDefault(T attrib, T default) { auto p = attrib im attributes; return p is null ? default : attrib; } //(4) Use Nullable!T (I prefer #5 over this one) Nullable!T attribOrNull(T attrib) { Nullable!T result; auto p = attrib ib attributes; if(p) result = *p; return result; } //(5) Use a pointer but not forward in operator. T* attribPtr(T attrib) { return attrib in attributes; } //(6) Throw exception (I only do this in combination with one of the above) T attribEx(T attrib) { return *enforce!AttribNotFoundEx(attrib in attributes); } } My personal preference using #2 and #3 in combination. #2 covers the basic case "Is this thing avalible?" and #3 covers the case "Give it to me if it is avalible or use this default value" I think it gives a clear image of what your code is doing at the callsite. Only using #2 or #3 limits you in this sence. For #1, #4 and #5 i personally stay away from them. They force the caller to either use an if or potentially trigger a null pointer derecerence. (Btw what is the benefit of #4? I have never used it since it seems pointless) I very rarly use attribEx. I don't think code shuld just spew exceptions all over the place. They should be reserved for really bad stuff, like bounds checks. One exception i make to this rule is if i'm dealing with ranges. Since the other methods don't lend themselfs for UFCS-chaing. |
February 04, 2014 Re: Templates: generic "return null;" | ||||
---|---|---|---|---|
| ||||
Posted in reply to TheFlyingFiddle | On Tuesday, 4 February 2014 at 00:43:54 UTC, TheFlyingFiddle wrote: > On Monday, 3 February 2014 at 10:25:19 UTC, Chris wrote: >> Is there a way I can make the return type in getAttribute generic? null does not work with numbers. >> >> MyStruct(T) { >> T[T] attributes; >> // .... >> public auto getAttribute(T attr) { >> if (!(attr in attributes)) { >> return null; // Doesn't work for numbers! >> } >> return attributes[attr]; >> } >> } >> >> void main() { >> auto myStr = MyStruct!int(0); // Error >> } > > Whenever i am faced with this situation i do one (or more then one) of the following things. > > struct MyStruct(T) > { > T[T] attributes; > > //(1) Forward the underlying access method Eg: > auto opBinaryRight(string s : "in")(T attrib) > { > return attrib in attributes; > } > > //(2) make a try method. > bool tryAttrib(T attrib, out T outAttrib) > { > auto p = attrib in attributes; > if(p) outAttrib = *p; > return p !is null; > } > > > > //(3) Give user option to set default value. > T attribOrDefault(T attrib, T default) > { > auto p = attrib im attributes; > return p is null ? default : attrib; > } > > > //(4) Use Nullable!T (I prefer #5 over this one) > Nullable!T attribOrNull(T attrib) > { > Nullable!T result; > auto p = attrib ib attributes; > if(p) result = *p; > return result; > } > > //(5) Use a pointer but not forward in operator. > T* attribPtr(T attrib) > { > return attrib in attributes; > } > > //(6) Throw exception (I only do this in combination with one of the above) > T attribEx(T attrib) > { > return *enforce!AttribNotFoundEx(attrib in attributes); > } > } Thanks for this brief outline. > My personal preference using #2 and #3 in combination. #2 covers the basic case "Is this thing avalible?" and #3 covers the case "Give it to me if it is avalible or use this default value" I think it gives a clear image of what your code is doing at the callsite. Only using #2 or #3 limits you in this sence. Personally I don't like the idea of passing a default value on the user side in this particular case. If the attribute has not been set, there is a reason, and I don't want to operate with a return value of something that has not been set at all. I introduced a check similar to #2: bool hasAttribute(T attr) { ... } Of course, the user has to use if. Experimentally, I introduced auto getAttribute(T attr) { if (!(attr in attributes)) { return T.init; } return attributes[attr]; } to avoid the if statement and just gently move along, if the attribute has not been set, which again leads to the problem of #3, i.e. potentially operating with a value of something that does not exist in the first place. > For #1, #4 and #5 i personally stay away from them. They force the caller to either use an if or potentially trigger a null pointer derecerence. (Btw what is the benefit of #4? I have never used it since it seems pointless) #4 is weird, but that's because I don't fully understand the concept behind it. > I very rarly use attribEx. I don't think code shuld just spew exceptions all over the place. They should be reserved for really bad stuff, like bounds checks. One exception i make to this rule is if i'm dealing with ranges. Since the other methods don't lend themselfs for UFCS-chaing. I agree. Exceptions should be reserved for serious cases or cases where you simply cannot predict all cases (reading random input from the internet, for example). |
February 07, 2014 Re: Templates: generic "return null;" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chris | Am Mon, 03 Feb 2014 10:25:17 +0000 schrieb "Chris" <wendlec@tcd.ie>: > MyStruct(T) { > T[T] attributes; > // .... > public auto getAttribute(T attr) { > if (!(attr in attributes)) { > return null; // Doesn't work for numbers! > } > return attributes[attr]; > } > } > > void main() { > auto myStr = MyStruct!int(0); // Error > } MyStruct(T) { T[T] attributes; // .... public auto getAttribute(T attr) { return attr in attributes; } } There you go. -- Marco |
Copyright © 1999-2021 by the D Language Foundation