Understanding the return type in a function - vb.net

There are examples I have seen where the return type mentioned in the function declaration is different from the default return type mentioned in the Return statement present in the body of the function. I am trying to understand how this works. For that I have come up with the following hypothetical example:
I had defined a class library MyMathsLibrary as following:
Public Class MathOperations
Public Function ADD(ByVal a As Integer, ByVal b As Integer) As Integer
Return a + b
End Function
End Class
Then I imported the above class Library into another class library named FactoryMathsLibrary as follows:
Imports MyMathsLibrary
Public Class Factory
Shared Function createMathsObject() As Object
Return New MathOperations()
End Function
End Class
Finally, I write the following code piece:
Imports FactoryMathsLibrary
Module Module1
Sub Main()
Dim a, b As Integer
Dim m As Object = Factory.createMathsObject()
Console.WriteLine(m.GetType())'O/P: MyMathsLibrary.MathOperations
Console.WriteLine("a + b = {0}", m.ADD(10, 5))
Console.WriteLine("a - b = {0}", m.Minus(20, 7))
Console.ReadLine()
End Sub
End Module
Question 1:
The function createMathsObject returns a reference which gets stored in the variable m. The output of the GetType command confirms that the reference that is returned points towards an instance of MathOperations class. So if that is the case what role does the word OBJECT play in the statement - Shared Function createMathsObject() As Object?
Related question:
Suppose there is an interface with only the ADD function in it and the class MathOperations implements the interface. In this case the variable m can be both of the Interface type as well as OBJECT type. In both cases it should be able to store the references that createMathsObject returns. In such a case, the good practice seems to be to declare m of interface type. My question is, is this because we need to avoid late binding wherever possible or is there any other reason? One drawback of declaring m to be of interface type (which could be a justification behind declaring m to be Object type) is that we cannot access elements which are not defined in the interface - for example if we declare m as object type and the interface has only the ADD method defined it it, we cannot write something like m.minus(a,b). Here MINUS should be assumed to be a function that calculates the difference between two values but is not a part of the Interface - rather its exclusive to the MathOperations class.

Related

How to determine the type of reference of ME?

Question:
In the below code, The O/P of Me.testShadow() when d.UseMe() gets executed, in my opinion should be "Shadowing Procedure: From the Derived Class". But instead the O/P that I am getting is "From Base Class: Shadowing procedure in derived class". I present my understanding as to why I think that the former should be output. PLease tell me where I am going wrong.
d is the derived class type reference pointing to an object of derived type.
d.UseMe() executes the statement Me.testShadow() inside it. ME behaves like an object variable pointing to the current instance, that is the object pointed to by "d". Therefore the reference that ME has is of derived class type.
testShadow() has two versions, one in the base class and the shadowing version in the derived class.
Since SHADOWS works on reference and since the type of ME reference is derived class type, I was expecting that the shadowing function in the derived class would be called? Instead, the testShadow() in the base class is being called.
Where am I mistaken? The code I wrote is given below:
Module Module1
Sub Main()
Dim b As New base()
Dim d As New derived()
d.useMe()
Console.ReadLine()
End Sub
End Module
Public Class base
Public Overridable Function testOverride() As String
Return "Overrideable function: From the base Class"
End Function
Public Function testShadow() As String
Return "From Base class. Shadowing function in inherited class"
End Function
Public Sub useMe()
Console.WriteLine("Me.testOverride() returns: {0}", Me.testOverride())
Console.WriteLine("Me.testShadow() returns: {0}", Me.testShadow)
End Sub
End Class
Public Class derived : Inherits base
Public Overrides Function testOverride() As String
Return "Overriden procedure: From derived class"
End Function
Public Shadows Function testShadow() As String
Return "Shadowing procedure: From derived class"
End Function
End Class
Overriding follows the type of the object, while shadowing follows the type of the reference. That useMe method is in the base class and Me will always be the type of the class it's used in, so Me is the base type. That means that Me.testShadow will execute the method in the base class.
You can easily prove to yourself that Me is type base by considering the fact that it is in a base class that could be inherited in any number of derived types. How could the type of the Me reference change depending on the derived type on which you called that method? References don't change type at run time. They are always whatever type they were when the code was compiled. That useMe method was written in the base class so it is type base and will always be that type.

Pass an argument to a generic type New constructor in VB.Net Generics

I'm trying to be able to pass a Type parameter to a function called ConvertList, and have that function create some instances of the specified type. So, if I passed in type Foo, the function would create new objects of type Foo and put the created objects into a custom List object (SLMR_OBjList).
The function is in a generic class that is defined:
Public Class BOIS_Collection_Base(Of T)
The function would accept types other than what is passed in the class definition. So, if we create an instance of BOIS_Collection_Base(Of MyTypeA) we may call the function ConvertList(Of MyTypeB).
I want the private variable _convertedList to be of a different type than the class. Is this possible? I can only seem to define it with (Of T).
Here is what I have so far:
Public Class BOIS_Collection_Base(Of T)
Private _convertedList As SLMR_ObjList(Of T) ' I can only seem to define this as (Of T), but want to make sure I can pass in a Type other than the Base(Of T)
Public Function ConvertedObjList(Of myT)() As SLMR_ObjList(Of T) ' Should this be (Of T) or (Of myT) since I want it to use whatever Type is passed in
For Each tempVar In Me.ObjList
Dim newitem As myT = Activator.CreateInstance(GetType(myT), tempVar)
' Next line won't compile, says on newitem 'Value of type 'myT' cannot be converted to 'T'
_convertedList.Add(newitem)
Next
_convertedList.Sort_Direction = Me.Sort_Direction
_convertedList.Sort_Expression_List = Me.Sort_Expression_List
Return _convertedList
End Function
Here is what I would like to be able to do:
Dim mainCollInstance As New BOIS_Collection_Base(Of MyTypeA)
....
'Code that populates the BOIS_Collection_Base.ObjList property with an SLMR_ObjList(Of MyTypeA)
....
' Now I want to take that ObjList, and cast all the items in it to MyTypeB
Dim newListObj As SLMR_ObjList(Of MyTypeB) = mainCollInstance.ConvertList(Of MyTypeB)
Is this possible? Am I going about it wrong?
In response to Plutonix:
If I define _convertedList inside the method, like this:
Public Function ConvertedObjList(Of myT)() As SLMR_ObjList(Of myT)
Dim _convertedList = New SLMR_ObjList(Of myT)
my errors go away, and the method does what I want, but _convertedList is no longer persistant in the object.
If you want to persist the list, then you can't really allow the consuming code to pass a different type for the list each time. That doesn't really make much sense, unless each time it's called, you only want the function to return the portion of the persisted list which contains objects of the given type. If that's the case, then you just need to declare _convertedList As SLMR_ObjList(Of Object) and then filter it and convert it to the correct type as necessary.
If, however, as I suspect is the case, the consumer will always be requesting that it be converted to the same type each time the function is called, then that output type is not really a property of the function call. Rather, it's a property of the whole class. In that case, you should make your class take two generic type arguments, like this:
Public Class BOIS_Collection_Base(Of T, TOut)
Private _convertedList As SLMR_ObjList(Of TOut)
Public Function ConvertedObjList() As SLMR_ObjList(Of TOut)
For Each tempVar As T In Me.ObjList
Dim newitem As TOut = DirectCast(Activator.CreateInstance(GetType(TOut), tempVar), TOut)
' Next line won't compile, says on newitem 'Value of type 'myT' cannot be converted to 'T'
_convertedList.Add(newitem)
Next
_convertedList.Sort_Direction = Me.Sort_Direction
_convertedList.Sort_Expression_List = Me.Sort_Expression_List
Return _convertedList
End Function
End Class
Based on the previous related question and an assumption that MyTypeA and MyTypeB inherit from the same class (never got an answer), you may not need Generics for this. At any rate, this should help with the ctor part of the question. I do not as yet see where Generics fit in since inheritance may do what you want already:
Class MustInherit BiosItem
Public Property Name As String
Public Property TypeCode As String
...
MustOverride Function Foo(args...) As Type
Overridable Property FooBar As String
' etc - the more stuff in the base class the better
End Class
Class TypeA
Inherits ABClass
Public Sub New
MyBase.New ' stuff common to all child types
TypeCode = "A" ' EZ type ID rather than GetType
...
End Sub
End Class
Class TypeB would be the same, but initialize TypeCode to "B". The same for C-Z. These allow you to poll the object rather than needing GetType: If thisObj.TypeCode = "A" Then.... Now, the collection class:
Public Class BIOSItems
Inherits Collection(Of BiosItem)
' inheriting from Collection<T> provides Add, Count, IndexOf for us
' most important the Items collection
'
End Class
Typing the collection as BiosItem will allow TypeA or TypeJ or TypeQ in it. As is, your collection will hold one Type only as it should be. This works because an item which is GetType(TypeA) is also GetType(BiosItem). See also note at the end.
Converting one item to another would seem to be something that would largely be handled by the NEW item being created or converted to. Since they are likely to be very similar then it can be handled by a constructor overload (if they are not similar, well we are well down the wrong road):
' a ctor overload to create the new thing based on the old things props
Public Sub New(oldThing As BiosItem)
MyClass.New ' start with basics like TypeCode, MyBase.New
With BiosItem ' coversion
myFoo = .Foo
myBar = .Bar ' copy common prop vals to self
...
Select Case .TypeCode
Case "B"
myProp1 = .Prop33 ' conversions
myProp3 = .Prop16 + 3.14
...
End Select
' then initialize stuff unique to this type maybe
' based on other props
If .PropX = "FooBar" Then myPropZ = "Ziggy"
End With
End Sub
Code to create, convert, store:
Dim varOldBItem As TypeB = myBiosCol(ndx) ' get old item
Dim varAItem As New TypeA(varOldBItem) ' call the ctor above
myBiosCol.Add(varAItem) ' add new item
myBiosCol.Remove(varoldBItem) ' delete the old if need be
If BOIS_Collection_Base is always supposed to contain MyTypeA, then type it that way (inheriting from Collection<T> still seems in order). If also MyTypeB objects are never added to the collection directly, but converted to MyTypeA first (Edit makes that less clear), then most of the above still applies, except for the inheritance. A ctor overload on MyTypeA could still take an old B object and create itself based on it. I'd be less inclined to do it via the ctor if they do not inherit from the same base class, but it could be done.

Covariant return types and static classes

Please have a look at the function below:
Public Function Test(ByVal i As Integer) As Animal
If i = 1 Then
Return New Dog
Else
Return New Cat
End If
End Function
A dog or a cat is returned by the function depending on whether the value of the integer is 1 or not. How is this approached if Dog and Cat are Static classes? i.e. you cannot create an instance of a static class. I have read a few webpages on the MSDN website this afternoon talking about static classes, but I have not found an answer to my specific question.
The term "static class" is a C# concept, it doesn't exist in VB.NET. So, no, this isn't possible.
It isn't possible in C# either, a static class can only derive from Object. The closest VB.NET equivalent of a static class is Module. Quite unsuitable.
You can certainly return a static instance of a class. Declare the variable in a Module or use the Shared keyword if you want to declare it inside a class.
Class Example
Private Shared theDog As Dog
Private Shared theCat As Cat
Public Shared Function Test(ByVal i As Integer) As Animal
If i = 1 Then Return theDog Else Return theCat
End Function
End Class
How is this approached if Dog and Cat are Static classes?
This isn't. You can't "return a static class" - you need to always return an object. You could use a static/shared method on a class to generate or operate on the object. For example, if you had a factory creation method on the types, you could do something like:
Public Function Test(ByVal i As Integer) As Animal
If i = 1 Then
Return Dog.Create(i)
Else
Return Cat.Create(i)
End If
End Function

Passing type argument to a generic custom class

I've seen a lot of chatter on this topic. Though the examples and desired outcomes are always very specific and specialized. Any direction on this is appreciated.
Custom Class:
Public Class customClass(Of T, S)
[include properties]
[include methods]
End Class
Implementation of Class:
dim [string] as string = string.empty
dim [type] as type = [string].gettype
dim instance as customClass(of [type], integer)
Also note, I've read that vb.net does not allow you to pass parameters to its constructor. I refuse to accept that you can't pass a type to a class and generate objects dependent on the type of that argument. Is the only answer to this a function in the class which returns a list of objects cast to the desired type? Your time is appreciated.
This question is motivated by academic research. The above is "what I am trying to do" thanks.
Kind of hard to see what you're trying to do, but if I'm reading this right, you're trying to take a variable and use that as the generic argument. This is not possible in .NET - when you declare a variable of a generic class, you need a compile-time type as the generic argument, so it cannot be the a variable of type Type.
This is important for a couple of reasons, one of which is to ensure that type constraints are met.
So:
Class Foo(Of T)
End Class
Dim x as Type = GetType(String)
Dim y as Foo(Of x)
does not work - you have to do:
Dim y as Foo(Of String)
There's always reflection and expression trees, but that's more of a hack than a solution.
You cannot use dynamic types to call this kind of typed declarations (Of t,s) but you can 'group' or delimit several types using interfaces or inheritance, which could also be very useful.
Class customClass(Of T As iMyInterface, s As iMyInterface)
End Class
Interface iMyInterface
End Interface
Class MyClass1
Implements iMyInterface
End Class
Class MyClass2
Implements iMyInterface
End Class
Dim y As New customClass(Of MyClass1, MyClass2)

What does VB.Net For Each Loop look at to Infer the Type

In the following code,
For Each item in MyCollection
...
Next
What does the compiler use to determine the type of item?
For example let say I have this class, which is inheriting a non generic collection,
Public Class BaseDataObjectGenericCollection(Of T)
Inherits BaseDataObjectCollection
End Class
A for each loop still infers the Item type as Object. How would I have to modify the above class to make the type inference work?
Edit: Per Beatles1692's answer, Implementing IEnumerator(Of T) kinda works. The base class already has a GetEnumerator function, inherited from CollectionBase, so I my implementation looked like this,
Public Function GetEnumerator1() As System.Collections.Generic.IEnumerator(Of T) Implements System.Collections.Generic.IEnumerable(Of T).GetEnumerator
Return MyBase.Cast(Of T)().GetEnumerator
End Function
However, the for loop still infers the type as object. But, if I change the interface implementation to this,
Public Shadows Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of T) Implements System.Collections.Generic.IEnumerable(Of T).GetEnumerator
Return MyBase.Cast(Of T)().GetEnumerator
End Function
That works, the for loop gets the type inference correct. So I guess the question is now, does For Each just look for a function called GetEnumerator ?
Well, there's only one place to go for a question like this. The spec!
Section 10.9.3 discusses For Each statements. According to it:
[if] local variable type inference is being used, then the identifier defines a new local variable whose scope is the entire For loop and whose type is the element type of the collection (Object if the enumerator expression is typed as Object).
"collection" here seems vague, but it's precisely defined on the next page. Essentially, the type must have a GetEnumerator() call, and this enumerator must (a) have a MoveNext() method that returns a boolean type, and (b) have a Current property. The type of the Current property is the type that will be inferred by the compiler. Note it actually has nothing to do with IEnumerator or IEnumerable...you just have to fit the prescribed pattern. Consider this code:
Option Infer On
Public Module M
Sub Main()
For Each x In New SomeClass()
Next
End Sub
End Module
Public Class SomeClass
Public Function GetEnumerator() As MyEnumerator
Return New MyEnumerator()
End Function
End Class
Public Class MyEnumerator
Public ReadOnly Property Current As Integer
Get
Return 42
End Get
End Property
Public Function MoveNext() As Boolean
Return True
End Function
End Class
The type of "x" in the Sub Main() is Integer, since the Current property returns Integer.
Either you should write :
For Each Item As SpecificType In MyCollection
....
Next
Then it will cast Item to SpecificType in each loop or your collection should have implemented IEnumerable(Of T)