Looking Zoran Horvats courses at PluralSight, I'm currently implementing a Maybe type, a bit like Zoran has on its GitHub account: https://github.com/zoran-horvat/option
Generally, a Maybe is a wrapper around objects, which are either set or have a null value, avoiding null reference exceptions.
To make the code a bit shorter, I would like to use implicit conversion to map the values / nulls to their corresponding maybe types. Here an example of my code:
public void Hook(Maybe<Action<Keys>> onKeyDown, Maybe<Action<Keys>> onKeyUp)
{
_keyDownCallback = onKeyDown;
_keyUpCallback = onKeyUp;
_hookService.Hook(HookType.KeyBoardLowLevel, OnHookReceived);
}
As you can see, you can hook and pass two optional callbacks, one for keyDown and one for keyUp. I would like to pass code like this:
nativeKeyboardHookService.Hook(new Action<Keys>(OnNativeKeyDown), null);
The implicit conversion on the Maybe is currently implemented like this:
public static implicit operator Maybe<T>(T value)
{
return ToMaybe(value);
}
public static implicit operator T(Maybe<T> maybe)
{
return ToT(maybe);
}
public static Maybe<T> ToMaybe(T value)
{
if (value == null)
{
return new None<T>();
}
return new Some<T>(value);
}
public static T ToT(Maybe<T> maybe)
{
return maybe.Evaluate(
value => value,
() => default(T));
}
My question: It works fine, if I pass an actual object, mapping it to an Maybe, but if I pass NULL, I still get a NULL object, not a None object. Am I doing here something wrong or is it just not possible? I didn't find any further information regarding such a conversion.
When you pass null to Hook() that's literally all you are doing because your implicit casts aren't being invoked at all. That's because null is a valid value for a reference type, and thus no need to cast.
You can't change Maybe to a struct if you want to keep Some and None because then these would have to be structs too, which means you run into the issue that you can't inherit structs.
You can't implement a common IMaybe<T> interface either because interfaces can't be used with casts.
What I recommend is keep your behavior as is, but don't use null. Instead of passing null, pass something else like Maybe<T>.None:
class Maybe<T>
{
public static Maybe<T> None { get; } = new None<T>();
}
void Hook(..., Maybe<T>.None) { ... }
Or None<T>.Instance:
class None<T>
{
public static None<T> Instance{ get; } = new None<T>();
}
void Hook(..., None<T>.Instance) { ... }
This has the advantage of being more readable and explicit.
Your Maybe<T> is still a reference type, so null is a valid value for it:
Maybe<string> foo = null;
If you want to prevent that, you will need to make it a value type, for example something like this:
public struct Maybe<T>
{
public T Value { get; }
public bool IsEmpty => Value == null;
public Maybe(T value)
{
Value = value;
}
public static implicit operator Maybe<T>(T value)
{
return new Maybe<T>(value);
}
}
Then you can pass null to a method expecting a Maybe<T> and it will properly construct an empty Maybe<T> object.
But note that it being a value type, this now means that it is copied on every method call, so it has a different behavior to a reference type implementation.
In the end, you cannot really implement this nicely in C# simply because there is the null reference in the language. It’s only with C# 8’s nullable reference types that you will be able to prevent nulls altogether.
Related
I'm implementing a C# variant of Haskell's Maybe and came across a weird issue where null and default has different implication on the value returned from an implicit conversion.
public class TestClass
{
public void Test()
{
Maybe<string> valueDefault = default;
Maybe<string> valueNull = null;
Maybe<string> valueFoobar = "foobar";
Console.WriteLine($"Default: (Some {valueDefault.Some}, None {valueDefault.None}");
Console.WriteLine($"Null: (Some {valueNull.Some}, None {valueNull.None}");
Console.WriteLine($"Foobar: (Some {valueFoobar.Some}, None {valueFoobar.None}");
}
}
public struct Maybe<T>
{
public T Some { get; private set; }
public bool None { get; private set; }
public static implicit operator Maybe<T>(T value)
{
return new Maybe<T>() {
Some = value,
None = value == null
};
}
}
The output being:
Default: (Some , None False)
Null: (Some , None True)
Foobar: (Some foobar, None False)
I was expecting both valueDefault and valueNull to be equal. But seems that null is converted while default isn't. I fixed the issue by replacing None with HasSome with a reversed boolean condition, but still the question remains.
Why is null and default treated differently?
Every type has a default value, including Maybe<T>. See this page for a list.
Maybe<string> valueDefault = default; will assign the default value of Maybe<string> to valueDefault. What's the default value of Maybe<string>? According to that page, since Maybe<string> is a struct, its default value is:
The value produced by setting all value-type fields to their default values and all reference-type fields to null.
So it's an instance of Maybe<string> with Some being null and None being false. false is the default value of bool.
The compiler doesn't try to use the default value of string, since that requires a further conversion to Maybe<string>. If it can just use the default value of Maybe<string>, why go the extra trouble, right?
You can force it to though:
Maybe<string> valueDefault = default(string);
null, on the other hand, gets converted to Maybe<string> because null is not a valid value of Maybe<string> (structs can't be null!), so the compiler deduces that you must mean null as string, and does the implicit conversion.
You might know this already, but you seem to be reinventing Nullable<T>
default always fills the memory of the struct with zero bytes. null is not a valid value for a value type, so the compiler discovers the implicit (Maybe<string>)(string)null cast.
Perhaps you could replace with;
public struct Maybe<T>
{
public T Some { get; private set; }
public bool None => Some == null;
...
I have a struct type in C#. I want to be able to convert null implicitly to this type. For instance, null could be represented by a special value of the struct type and the cast operator should return a struct with this value.
In C++, I could use an implicit cast operator overload of type std::nullptr_t. Is there a comparable type in C#?
I have had the idea to use a special NullType class which has no instances. This works but looks somehow ugly. Is there a better way?
Example:
class NullType
{
private NullType(){} // ensures that no instance will ever be created
}
struct X
{
private static readonly int nullValue = -1;
private int val;
public X(int val){ this.val= val; }
public static implicit operator X(NullType t)
{
return new X(nullValue);
}
}
class MainClass
{
public static void Main(string[] args)
{
X x = null; // Works now!
}
}
No, conversion operators only allow conversion from types, not from a specific value of a type, aka null, so there is no null conversion operator.
The best fitting operator without introducing own types would be this:
public static implicit operator X(object t)
But obviously you don't want to use this. It isn't very safe to use (t can be any value, and the only way to handle non-null cases in an exception).
That said, I think the way you've created it now, using a class that can't be initialized is the best way to do this. In fact the only question is: why do you want to use null, instead of 'just' an default value instance on your struct (X.Null).
Suppose I have the following class:
public class GenericClass<T>
{
public T Find()
{
//return T if found otherwise null or Nullable<T>
}
}
Somewhere I'd like to specialize my class using T with a class, other times with a struct.
I'm facing this issue: I can't return a Nullable<T> if T type isn't restricted to be a struct.
I would like to provide an implementation of my Find method that works if T is specialized with both a class or a struct.
In case Find fails , I'd like to return null if T is a class otherwise Nullable<T>.
Is that possible without using reflection? If yes how?
You can return default(T).
For a class, this will be null. For any Nullable<T>, this will be a Nullable<T> without a value (effectively null).
That being said, if you use this with a struct and not a Nullable<T> as the type, default(T) will be the default value of the struct.
If you want to make this work uniformly for any class or struct, you would likely need to return two values - you could use the framework as inspiration here, and have a TryXXX method, ie:
public bool TryFind(out T)
You could then use default(T) when the value isn't found, and return false. This avoids the need for nullable types. You could also write this returning a Tuple<bool, T> or similar, if you wanted to avoid the out parameter, ie:
public Tuple<bool, T> Find()
A final option, potentially, would be to make your class non-generic, then use a pair of generic methods:
class YourClass // Non generic
{
public T FindReference<T>() where T : class
{
// ...
return null;
}
public Nullable<T> FindValue<T>() where T : struct
{
// ...
return default(T);
}
}
Note that you need distinct names, since you can't have an overloaded method purely based on the return type.
I would use the following solution:
public Boolean Find(out T result)
{
// Pseudo code
if (FindItem == true)
{
result = ItemFound;
return true;
}
result = default(T);
return false;
}
Why? Because Nullable<T> only accepts a struct and the method above supports both, classes and structs.
As Reed said you could return default(T).
In my opinion this has one big disadvantage: If your method states that default(T) is returned if the item was not found, you lose the ability to return the default values for value types (e.g. returning 0 for Find<int> might generally be a perfectly valid return value).
I would rather go for something like this
public class GenericClass<T>
{
public Option<T> Find()
{
//return Option.Some(item) if found otherwise Option.None<T>()
}
}
public static class Option
{
public static Option<T> None<T>()
{
return new Option<T>(default(T), false);
}
public static Option<T> Some<T>(T value)
{
return new Option<T>(value, true);
}
}
public sealed class Option<T>
{
private readonly T m_Value;
private readonly bool m_HasValue;
public void Option(T value, bool hasValue)
{
m_Value = value;
m_HasValue = hasValue;
}
public bool HasValue
{
get { return m_HasValue; }
}
public T Value
{
get { return m_Value; }
}
}
I'm trying to find the right thing to do with a non-null validation on a nullable boolean. I also want to be able to do the same thing with some other fields, including strings, ints, etc., so I want to use generics for the method. Here's an example of the kind of thing which can happen.
bool? myValue = null;
bool valid = ValidateNotNull(myValue);
And here's some validation code:
public bool ValidateNotNull<T>(T nullableField)
{
return nullableField != null;
}
All the answers I've found to this kind of problem suggest adding a where T : struct or where T: class to the method signature, or using default(T) in the comparison, none of which will work for a bool where false is a valid value.
Any other suggestions? The code compiles, but Resharper isn't happy about that null comparison on a value which it thinks might be a primitive, and I'd love to know what I should be doing to cheer it up.
NB: This isn't the complete code. I'm still interested in maintaining the type. This is also not the only place I've run into the problem.
NB2: Yes, it compiles and works fine. What I really want to know is whether there is a code solution for stopping Resharper from complaining, or an idiomatic way to do this which I don't know about.
The code below will validate nullable types and reference types:
public bool ValidateNotNull<T>(Nullable<T> nullableField) where T:struct
{
return nullableField.HasValue;
}
public bool ValidateNotNull<T>(T nullableField) where T:class
{
return nullableField!=null;
}
Would comparing to default work?
public bool ValidateNotNull<T>(T nullableField)
{
return Equals(nullableField, default(T));
}
Updated:
Either its a primitive, and all is well, or its not null:
public bool ValidateNotNull<T>(T nullableField)
{
return typeof(T).IsPrimitive || !Equals(nullableField, null);
}
I also want to be able to do the same thing with some other fields, including strings, ints, etc
OK, so you want a method that can be passed either a Nullable<> (which is a struct), or a reference type, and will return true iff the argument is null (note that your name appears to be the wrong way round, but there you go).
The thing is, if that's all this method has to do, then you don't need generics because you don't need type-safety. This example works and does what you want, I think:
class Program
{
static void Main(string[] args)
{
int? x = null;
int? y = 5;
string s = null;
string r = "moo";
Console.WriteLine(ValidateNotNull(x));
Console.WriteLine(ValidateNotNull(y));
Console.WriteLine(ValidateNotNull(s));
Console.WriteLine(ValidateNotNull(r));
Console.ReadLine();
}
private static bool ValidateNotNull(object o)
{
return o == null;
}
}
This outputs
True
False
True
False
which is I believe your required output.
I don't know why you thing your method doesn't work (apart from using != rather than ==), because as far as I can tell, it already works! You can compare any value of type T with null (when T is a generic type parameter). If a non-nullable value type is used for T, the result will be treated as a constant (false for == null, true for != null).
So, this should be fine.
public bool ValidateNotNull<T>(T nullableField)
{
return nullableField != null;
}
But this would also work without generics:
public bool ValidateNotNull(object nullableField)
{
return nullableField != null;
}
(Because boxing a Nullable<T> null value returns a null reference.)
You need to use
public bool ValidateNotNull<T>(T nullableField)
{
return nullableField.HasValue;
}
I alredy have this:
public static object GetDBValue(object ObjectEvaluated)
{
if (ObjectEvaluated == null)
return DBNull.Value;
else
return ObjectEvaluated;
}
used like:
List<SqlParameter> Params = new List<SqlParameter>();
Params.Add(new SqlParameter("#EntityType", GetDBValue(EntityType)));
Now i wanted to keep the same interface but extend that to use it with nullable
public static object GetDBValue(int? ObjectEvaluated)
{
if (ObjectEvaluated.HasValue)
return ObjectEvaluated.Value;
else
return DBNull.Value;
}
public static object GetDBValue(DateTime? ObjectEvaluated)
{...}
but i want only 1 function GetDBValue for nullables. How do I do that and keep the call as is is? Is that possible at all?
I can make it work like:
public static object GetDBValue<T>(Nullable<T> ObjectEvaluated) where T : struct
{
if (ObjectEvaluated.HasValue)
return ObjectEvaluated.Value;
else
return DBNull.Value;
}
But the call changes to:
Params.Add(new SqlParameter("#EntityID ", GetDBValue<int>(EntityID)));
The generic version that you have is fine, although you can shorten it even more with the null-coalescing operator:
public static object GetDBValue<T>(Nullable<T> ObjectEvaluated)
where T : struct
{
return ObjectEvaluated ?? (object)DBNull.Value;
}
What you might be missing is that you don't need to use the generic parameter when you call it; C#'s type inference will figure it out for you:
int? x = null;
object y = GetDBValue(x);
If EntityID (in your last example) is a Nullable type then the compiler will know to call GetDBValue without specifying the underlying type.
I'm not sure there is much point doing that; what you have already boxes (since it returns object), you might as well let the CLR do that for you. Simply:
public static object GetDBValue(object ObjectEvaluated)
{
return ObjectEvaluated ?? DBNull.Value;
}
There isn't much benefit adding generics here (since we don't use the T).
You certainly could add a generic method, but what does it add?