I’m struggling to implement a maybe monad – which I’ve called Nullable in this example.
The Nullable Class is implemented as follows:
Public NotInheritable Class Nullable(Of TClass)
Private _value As TClass
Private _hasValue As Boolean
Public Shared Function Create(ByVal value As TClass) As Nullable(Of TClass)
Return New Nullable(Of TClass)(value)
End Function
Public Shared Function Create() As Nullable(Of TClass)
Return New Nullable(Of TClass)()
End Function
Private Sub New()
HasValue = False
End Sub
Private Sub New(theValue As TClass)
Value = theValue
HasValue = True
End Sub
Public Property Value() As TClass
Get
Return _value
End Get
Private Set(value As TClass)
_value = value
End Set
End Property
Public Property HasValue() As Boolean
Get
Return _hasValue
End Get
Private Set(value As Boolean)
_hasValue = value
End Set
End Property
End Class
There is a parent Class implemented as
Class Parent
Public Property ChildClass as Nullable(Of Child)
End Class
and a Child Class is simply
Class Child
Public Property ID as String
... other properties below ...
End Class
The way the monad is implemented at the moment I would need to issue the following to access a property on the nested child class
dim id = MyParentClass.ChildClass.Value.ID
but ideally what I’d like to be able to do is to have the following statement
dim id = MyParentClass.ChildClass.Id
and if the ChildClass is null then just return a default value for the property type.
I tried implementing this using Default Properties and setting the Value as default via an attribute but it wouldn’t compile.
Is that going to be possible or perhaps there is a better way of architecting it – or maybe I just haven’t ‘got’ the maybe monad?
Many TIAs
Simon
Well, the definition of
Maybeitself is simply a single value that may or may not be present, so that much is fine. Incidentally, if you don’t like the name “Maybe” for some reason, I’d suggest considering “Option” instead of “Nullable”, sinceNullableis already used by .NET (for the same purpose, even–but only with value types), whileOptionis what F# calls it and consistency is nice.Anyway, there are essentially two things you can do with such a value–apply a transformation to the value (if there is one), and collapse nested layers (e.g., turning a nullable of a nullable of “foo” into just a nullable of “foo”). You can do everything else given those and the ability to construct new values.
The “transform” operation is most straightforwardly implemented by taking a lambda (compare the
Selectmethod used by LINQ–it’s the same thing), and either applying it to the wrapped value or discarding it if there is no value. The “collapse” operation is pretty simple; just keep the inner value if it exists. LINQ is a very natural approach here–you can think ofMaybeas representing an enumerable sequence of at most one element.That said, you probably don’t want to be using lambdas or LINQ expressions everywhere. The bad news is that I don’t think there’s any other way.
What I suspect you really want here is to apply the “transform” operation implicitly using regular method call syntax, while automatically applying the “collapse” operation if the method also returns something nullable, and possibly providing a default value when attempting to use a missing value directly. This is a reasonable design, and very handy to use, but I don’t think it’s possible here (I’ve tried a couple variations myself using C#, and I don’t think VB.NET differs enough to help). The end result of a scheme like this is the ability to call methods on null values, and get a null value back instead of a null reference exception. As an illustration, here’s something similar in Ruby, implemented with a bit of metaprogramming trickery that I don’t think VB.NET can support. I vaguely recall seeing similar ideas done in Javascript and some other languages.
In short, I think you have basically the right idea but what you’re trying to accomplish sadly isn’t possible.