Replies: 16 comments
-
With a bit of tweaking, this idea could lead us to a very good place: a Many people use nullable as a maybe construct: However, we still have the dreaded The final step could be achieved through having a bottom type, which has the single "value": This would then mean that code like the following becomes possible: T? TryFoo<T>() => ...
var x = TryFoo<SomeClass>(); // x is SomeClass?
if (x.HasValue) // HasValue is implemented by bottom type. null.HasValue avoids NRE
{
// x is not null here; flow analysis understands this and can treat x as SomeClass
}
else
{
var y = x.ToString(); // ToString implemented by bottom. null.ToString() returns "null"
var z = x.Bar(); // compiler warning as x is null
} |
Beta Was this translation helpful? Give feedback.
-
Why woudl you need this? Fraction is already a struct, and so can't be null. If you want to support the null value, you can. with Appropriately this would have no relation to null/nullable/etc. because your helpful sentinel value is not null. It's a real value, just one (of potentially many) that you don't consider valid in your domain (but which are totally valid in the entire .net domain). Also... if you really want to compare your type to null (like you have in your code), why not just add: public static bool operator==(Fraction f, Fraction? f2) { return true; } ? With that, you can write You can also overload |
Beta Was this translation helpful? Give feedback.
-
Because it provides a solution to coping with default structs that have an invalid/meaningless value, such as Fraction f = default; // compiler warning: assigning a possible null to a Fraction variable If we took this a step further and eg decorated the operator with information on when it'll be null: [NullOnDefault]
public static bool operator?(Fraction value) => Number == 0 && Divider == 0; Then that compiler warning can be definite over the null state, rather than warning on a "possible null". |
Beta Was this translation helpful? Give feedback.
-
@CyrusNajmabadi It just that
var text = someClass?.NullableStruct?.ToString(); Not only that, one thing I want is custom nullable type. Because we have |
Beta Was this translation helpful? Give feedback.
-
There are already existing solutions for copying with that :) For example, ImmutableArray has "IsDefault". I also showed how you can provide your own custom equality if you want your "invalid" values to somehow have a relation to "null" values. It's unclear why a new language feature is needed here. |
Beta Was this translation helpful? Give feedback.
-
Why can't you make your own custom nullable? And just define appropriate operators on it (like operator==)? |
Beta Was this translation helpful? Give feedback.
-
@CyrusNajmabadi I don't add new feature here. I just want to make alike pattern can reuse same operator for the same intention In my opinion |
Beta Was this translation helpful? Give feedback.
-
I disagree. Note, for example, that you cannot use ?. on a reference type to test it for other potential 'invalid values' that you might see in your domain.
I would personally not like that. Because now i have to know that these operators now have potentially special meaning for your particular domain. That means, for example, that i might know that a value was non-null, but then i'd see a ?. which i would then think was inappropriate. However, removing the ?. would change code meaning as you were not just testing for null, but also your special 'invalid' values in your particular domain. |
Beta Was this translation helpful? Give feedback.
-
Note: having actual named accessors here seems far better as it actually conveys how the values are special and why you might need to care. Consider how this is handled for floating point values. There are values like infinities, and nans, and whatnot. Because of how they all may need to be specially handled, it's important to be able to tell which is which, and not just have them all bucketed together. Nice names make it clear what's happening. The same holds for something like ImmutableArray. It has a 'default' state (as it's a struct) which you can check for with .IsDefault. But you can also check .IsEmpty as well as having hte convenience '.IsDefaultOrEmpty'. These names make it clear what is being tested and what the state of the value is if the test is true or not. Rolling these up into generic operators makes the code less clear as now i have to know how you applied that operator to your domain. Today, i know exactly what the operators mean across all domains, and i can reason about them as such. Removing that understanding seems like a bitter pill to swallow. |
Beta Was this translation helpful? Give feedback.
-
With this proposal, you could. eg, class Foo
{
bool _valid;
...
public static bool operator ?(Foo value) => value is null || !_valid;
}
var x = new Foo(); // Foo is invalid by default
var y = x?.Bar(); // Bar isn't called and y is null as ? operator returns false |
Beta Was this translation helpful? Give feedback.
-
@CyrusNajmabadi It's understandable that you would disagree but please understand that this feature was created on this thought
When I write this issue I'm also not sure that should we allow class to override this pattern too or not. But there are an example in unity3D So if we let struct can override this, maybe class should be able to too
I think opposite to that. If any struct can use |
Beta Was this translation helpful? Give feedback.
-
@CyrusNajmabadi For me |
Beta Was this translation helpful? Give feedback.
-
Sure. For you :) That's why it's domain specific. The point is that names allow it to be very clear what's actually going on, and to allow the consumer to decide what's going on and how they would want to make sense of it. |
Beta Was this translation helpful? Give feedback.
-
This sounds like another case which #727 could resolve. It wouldn't look exactly the same way in code, but it could accomplish the same underlying goals (preventing the use of invalid/uninitialized values). |
Beta Was this translation helpful? Give feedback.
-
I really like this proposal and I would like the operator to also apply to classes that act like wrappers (which is how it is applied today). A Maybe{T} or WeakReference{T} should return a {T} in the '?' operator when valid (just like Nullable{T}). The signature could be like this: class Foo
{
public static bool operator ?(Foo value, out Bar result) ...
...
} Changing Bar to Foo allows for self-validating classes. For example a Maybe class would be: class Maybe<T>
{
public static bool operator ?(Maybe<T> value, out T result)
{
var valid = !(value is null) && value.HasValue;
result = valid ? value.Value : default;
return valid;
}
Maybe() ...
bool HasValue ...
T Value ...
} And used like this: class Bar
{
void DoSomething() ...
}
var x = new Maybe<Bar>();
...
x?.DoSomething(); Theres is drawback in that the operator loses the guarateed thread-safe calling when overriding the behavior, leaving to the implementer the burden of ensuring thread-safety. |
Beta Was this translation helpful? Give feedback.
-
@CyrusNajmabadi I agree that there is always high risk when overloading operators. They should be carefully documented and do what the user would expect. Applying it to double would be a mistake, because it is as domain-agnostic as it comes. But the pattern of checking if a value or class is valid before calling (more-so when an exception is the alternative) is frequent enough that I believe it warrants the expansion of the operator semantics to shorten the code written; just as the pattern of checking nullability warranted the creation of the operator in the first place. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Revise from #494 to allow nullable operator
?.
and??
for any structBeta Was this translation helpful? Give feedback.
All reactions