How do I specify Enumerable.Count() instead of List.Count? - vb.net

When attempting to use the Enumerable.Count() extension method from Visual Basic, the following code results in a compile-time error:
Imports System.Linq
Module Module1
Sub Main()
Dim l As New List(Of Foo) From {New Foo("a"), New Foo("b"), New Foo("a")}
Dim i As Integer = l.Count(Function(foo) foo.Bar = "a")
Console.WriteLine(i)
Console.ReadLine()
End Sub
Class Foo
Sub New(ByVal bar As String)
Me.Bar = bar
End Sub
Public Property Bar As String
End Class
End Module
The error produced is:
'Public ReadOnly Property Count As Integer' has no parameters and its
return type cannot be indexed.
I'm targeting .NET 4.0, so extension methods should be supported. It's also worth noting that the equivalent code in C# infers the extension method correctly...
Why is the compiler unable to infer the use of Enumerable.Count, given the predicate I'm passing as an argument, and how can I use the extension method instead of the List's Count property?

The VB.Net compiler first tries to look up Count on the List instance, and it finds the Count property. This property is used instead of the extension method since fields and properties always shadow extension methods by name. I don't know where this is stated in the Visual Basic Language spec, but you can read more in this MSDN Magazin article:
Fields and properties always shadow extension methods by name. Figure 4 shows an extension method and public field with the same name and various calls. Though the extension method contains a second argument, the field shadows the extension method by name and all calls using this name result in accessing the field. The various overloaded calls will all compile, but their results at run time may be unexpected since they will bind to the property and use the default property behavior to return a single character or result in a runtime exception. It is important to choose the names of your extension methods so you avoid clashes with properties, fields, and existing instance methods.
So, Count(Function(foo) foo.Bar = "a") could mean: call the Count-property with Function(foo) foo.Bar = "a", or take the result of the Count-property and index it with Function(foo) foo.Bar = "a", which could be totally valid, since indexed properties in VB.Net can take any parameter.
This works in C# (I guess) because it is easier for the C# compiler to distinguish between method calls and a property access, because unlike VB.Net C# does not allow arbitrary parameters on properties and indexed properties.
To use the extension method, you call it like you would call every other static (shared) method:
Dim i As Integer = Enumerable.Count(l, Function(foo) foo.Bar = "a")
or call Call on IEnumerable explicitly:
Dim i As Integer = l.AsEnumerable().Count(Function(foo) foo.Bar = "a")

To answer your question as to why VB can't do what C# can in this case...
VB lets you access properties with () after the name, and also lets you call functions with no parameters by omitting the (). Also indexers use rounded brackets, instead of square brackets you have in C#. These are examples of tremendous VB features designed to make programming easier, which actually results in more ambiguous, harder to understand, and bug prone code.
So, in this particular case, VB sees you are accessing Count, and assumes the brackets after it are an indexer to the Count property, rather than arguments to the Count function.
C# sees the rounded brackets, and realises that you aren't accessing the indexer, you must be calling a function, so looks for a function.
Of course, there's room for ambiguity in C# as well. For example, a property with the same name as an extension method, which returns a delegate type will be called in preference to the extension method...
public Action Count { get; set; }
Ah... happy days.
As to how to call the IEnumerable.Count() function, a cast (preferably DirectCast()) or executing the extension method directly Enumerable.Count(...), is far far preferable to creating a whole new array to call count on...!

I'm not sure as to why you aren't getting the overload as an option, but you should be able to cast the list to IEnumerable(Of Foo) at which point the compiler will no longer allow List(Of Foo).Count property.
CType(l, IEnumerable(Of Foo)).Count(Function(foo) foo.Bar = "a")

If the list is converted to an array it works
Dim l As New List(Of Foo) From {New Foo("a"), New Foo("b"), New Foo("a")}
Dim i As Integer = l.ToArray.Count(Function(x) x.Bar = "a")

Related

Identical objects in a list produce different hashes and fail comparison tests

I have a weird issue. I want to implement an extension to List with a function to merge another list into it excluding the duplicate values:
<Extension()>
Public Sub AddUnique(Of T)(ByVal self As IList(Of T), ByVal items As IEnumerable(Of T))
For Each item In items
If Not self.Contains(item) Then self.Add(item)
Next
End Sub
Now, I have a class that I'll be creating objects from, and adding them to a list:
Class DocInfo
Public Property title As String
Public Property fullPath As String
Sub New(title As String, fullPath As String)
Me.title = title
Me.fullPath = fullPath
End Sub
End Class
Then, I have a list as a global variable:
Public docsInfo As New List(Of DocInfo)
And then I have a button handler that adds new items to that list:
Private Sub AddToList_Button_Click(sender As Object, e As RoutedEventArgs)
Dim candidateItems As New List(Of DocInfo)
For Each doc In selectedDocs
candidateItems.Add(New DocInfo(doc.GetTitle(), doc.GetPathName()))
Next
docsInfo.AddUnique(candidateItems)
End Sub
(The doc and selectedDocs variables are outside of the scope of this question.)
Now, the important bit - GetTitle() and GetPathName() return the same strings on every button click (I have the same docs selected between clicks). Meaning that DocInfo objects that are added to the candidateItems, and then added to docsInfo, are identical. Nevertheless, the extension function AddUnique fails, resulting in duplicates in the list.
Puzzled, I ran GetHashCode() on these duplicate DocsInfo class objects:
For Each docInfo In docsInfo
Console.WriteLine(docInfo.title)
Console.WriteLine(docInfo.fullPath)
Console.WriteLine(docInfo.GetHashCode())
Next
And this is the output:
Assem1^Test assembly.SLDASM
C:\Users\Justinas\AppData\Local\Temp\swx5396\VC~~\Test assembly\Assem1^Test assembly.SLDASM
7759225
Assem1^Test assembly.SLDASM
C:\Users\Justinas\AppData\Local\Temp\swx5396\VC~~\Test assembly\Assem1^Test assembly.SLDASM
14797678
With each button click, I am getting identical DocsInfo objects (title and fullPath properties have the same values), yet their hashes are different every time, and every comparison I can think of, fails to acknowledge that these objects are for all intents and purposes idendical.
Why is this happening? And how can I fix the AddUnique extension function to work as intended?
This behavior is because of the difference in .NET between "Reference" types and "Value" types. The fundamental philosophy of these is that for "Reference" types, object identity takes precedence over contents (that is, two different object instances with the same contents are still considered distinct), while for "Value" types, the contents are the only thing that matters.
In VB, Class denotes a reference type while Structure denotes a value type. Their respective behaviors are what you would expect, then: by default, Equals on a Class is equivalent to ReferenceEquals, checking to see if the references are the same, and GetHashCode returns a value based on the object identity. Equals on a Structure does member-wise value equality, and GetHashCode returns a value based on the hash codes of the members.
There are a couple of different options for overriding the default behavior, with differing impacts and levels of intrusiveness.
You can change Class to Structure. If you do so, I would strongly recommend to eliminate any mutable behavior on them (i.e. make all fields and properties ReadOnly), because mutable Structures can be extremely hard to reason about correctly. If you really do have immutable data, though, this is the easiest to maintain because .NET will already do what you want, you don't have to maintain your own Equals or GetHashCode override.
You can override GetHashCode and Equals on your Class to act like the Structure versions. This won't change anything else about your class, but it will make it act like a value type for the purposes of containers and sequences. If you're worried about maintenance, an alternative would be to do something reflection-based, though this shouldn't be used for anything that will be high-throughput because reflection is generally not particularly performant.
I believe the hashing and ordering containers take optional constructor parameters that will let you provide a class for overriding the behavior of the contents without altering the Class itself. You could do something like this. I'd recommend to look at the MSDN docs for HashSet.

Do I understand not using getters and setters correctly

After reading this piece by Yegor about not using getters and setters, it sounds like something that makes sense to me.
Please note this question is not about whether doing it is better/worst, only if I am implementing it correctly
I was wondering in the following two examples in VBA, if I understand the concept correctly, and if I am applying it correctly.
The standard way would be:
Private userName As String
Public Property Get Name() As String
Name = userName
End Property
Public Property Let Name(rData As String)
userName = rData
End Property
It looks to me his way would be something like this:
Private userName As String
Public Function returnName() As String
returnName = userName
End Function
Public Function giveNewName(newName As String) As String
userName = newName
End Function
From what I understand from the two examples above is that if I wanted to change the format of userName (lets say return it in all-caps), then I can do this with the second method without changing the name of the method that gives the name through - I can just let returnName point to a userNameCaps property. The rest of my code in my program can still stay the same and point to the method userName.
But if I want to do this with the first example, I can make a new property, but then have to change my code everywhere in the program as well to point to the new property... is that correct?
In other words, in the first example the API gets info from a property, and in the second example the API gets info from a method.
Your 2nd snippet is neither idiomatic nor equivalent. That article you link to, is about Java, a language which has no concept whatsoever of object properties - getFoo/setFoo is a mere convention in Java.
In VBA this:
Private userName As String
Public Property Get Name() As String
Name = userName
End Property
Public Property Let Name(rData As String)
userName = rData
End Property
Is ultimately equivalent to this:
Public UserName As String
Not convinced? Add such a public field to a class module, say, Class1. Then add a new class module and add this:
Implements Class1
The compiler will force you to implement a Property Get and a Property Let member, so that the Class1 interface contract can be fulfilled.
So why bother with properties then? Properties are a tool, to help with encapsulation.
Option Explicit
Private Type TSomething
Foo As Long
End Type
Private this As TSomething
Public Property Get Foo() As Long
Foo = this.Foo
End Property
Public Property Let Foo(ByVal value As Long)
If value <= 0 Then Err.Raise 5
this.Foo = value
End Property
Now if you try to assign Foo with a negative value, you'll get a runtime error: the property is encapsulating an internal state that only the class knows and is able to mutate: calling code doesn't see or know about the encapsulated value - all it knows is that Foo is a read/write property. The validation logic in the "setter" ensures the object is in a consistent state at all times.
If you want to break down a property into methods, then you need a Function for the getter, and assignment would be a Sub not a Function. In fact, Rubberduck would tell you that there's a problem with the return value of giveNewName being never assigned: that's a much worse code smell than "OMG you're using properties!".
Functions return a value. Subs/methods do something - in the case of an object/class, that something might imply mutating internal state.
But by avoiding Property Let just because some Java guy said getters & setters are evil, you're just making your VBA API more cluttered than it needs to be - because VBA understands properties, and Java does not. C# and VB.NET do however, so if anything the principles of these languages would be much more readily applicable to VBA than Java's, at least with regards to properties. See Property vs Method.
FWIW public member names in VB would be PascalCase by convention. camelCase public member names are a Java thing. Notice how everything in the standard libraries starts with a Capital first letter?
It seems to me that you've just given the property accessors new names. They are functionally identical.
I think the idea of not using getters/setters implies that you don't try to externally modify an object's state - because if you do, the object is not much more than a user-defined type, a simple collection of data. Objects/Classes should be defined by their behavior. The data they contain should only be there to enable/support that behavior.
That means you don't tell the object how it has to be or what data you want it to hold. You tell it what you want it to do or what is happening to it. The object itself then decides how to modify its state.
To me it seems your example class is a little too simple to work as an example. It's not clear what the intended purpose is: Currently you'd probably better off just using a variable UserName instead.
Have a look at this answer to a related question - I think it provides a good example.
Regarding your edit:
From what I understand from the two examples above is that if I wanted
to change the format of userName (lets say return it in all-caps),
then I can do this with the second method without changing the name of
the method that gives the name through - I can just let returnName
point to a userNameCaps property. The rest of my code in my program
can still stay the same and point to the method iserName.
But if I want to do this with the first example, I can make a new
property, but then have to change my code everywhere in the program as
well to point to the new property... is that correct?
Actually, what you're describing here, is possible in both approaches. You can have a property
Public Property Get Name() As String
' possibly more code here...
Name = UCase(UserName)
End Property
or an equivalent function
Public Function Name() As String
' possibly more code here...
Name = UCase(UserName)
End Function
As long as you only change the property/function body, no external code needs to be adapted. Keep the property's/function's signature (the first line, including the Public statement, its name, its type and the order and type of its parameters) unchanged and you should not need to change anything outside the class to accommodate.
The Java article is making some sort of philosophic design stance that is not limited to Java: The general advise is to severely limit any details on how a class is implemented to avoid making one's code harder to maintain. Putting such advice into VBA terms isn't irrelevant.
Microsoft popularized the idea of a Property that is in fact a method (or two) which masquerade as a field (i.e. any garden-variety variable). It is a neat-and-tidy way to package up a getter and setter together. Beyond that, really, behind the scenes it's still just a set of functions or subroutines that perform as accessors for your class.
Understand that VBA does not do classes, but it does do interfaces. That's what a "Class Module" is: An interface to an (anonymous) class. When you say Dim o As New MyClassModule, VBA calls some factory function which returns an instance of the class that goes with MyClassModule. From that point, o references the interface (which in turn is wired into the instance). As #Mathieu Guindon has demonstrated, Public UserName As String inside a class module really becomes a Property behind the scenes anyway. Why? Because a Class Module is an interface, and an interface is a set of (pointers to) functions and subroutines.
As for the philosophic design stance, the really big idea here is not to make too many promises. If UserName is a String, it must always remain a String. Furthermore, it must always be available - you cannot remove it from future versions of your class! UserName might not be the best example here (afterall, why wouldn't a String cover all needs? for what reason might UserName become superfluous?). But it does happen that what seemed like a good idea at the time the class was being made turns into a big goof. Imagine a Public TwiddlePuff As Integer (or instead getTwiddlePuff() As Integer and setTwiddlePuff(value As Integer)) only to find out (much later on!) that Integer isn't sufficient anymore, maybe it should have been Long. Or maybe a Double. If you try to change TwiddlePuff now, anything compiled back when it was Integer will likely break. So maybe people making new code will be fine, and maybe it's mostly the folks who still need to use some of the old code who are now stuck with a problem.
And what if TwiddlePuff turned out to be a really big design mistake, that it should not have been there in the first place? Well, removing it brings its own set of headaches. If TwiddlePuff was used at all elsewhere, that means some folks may have a big refactoring job on their hands. And that might not be the worst of it - if your code compiles to native binaries especially, that makes for a really big mess, since an interface is about a set of function pointers layed out and ordered in a very specific way.
Too reiterate, do not make too many promises. Think through on what you will share with others. Properties-getters-setters-accessors are okay, but must be used thoughtfully and sparingly. All of that above is important if what you are making is code that you are going to share with others, and others will take it and use it as part of a larger system of code, and it may be that these others intend to share their larger systems of code with yet even more people who will use that in their even larger systems of code.
That right there is probably why hiding implementation details to the greatest extent possible is regarded as fundamental to object oriented programming.

best matching overloaded method is not being called

I have the following methods:
Public Function RenderRateTable() As String
Private Function RenderRateTable(ToddVersionedObject As ToddVersionedObject,
FieldInfo As FieldInfo) As String
Private Function RenderRateTable(ArrayIndexes As List(Of ArrayIndexesAttribute.ArrayIndex),
ThreeDimensionalArray As ThreeDimensionalDecimalArrayType) As String
Private Function RenderRateTable(ArrayIndexes As List(Of ArrayIndexesAttribute.ArrayIndex),
TwoDimensionalArray As ArrayOfDecimalArraysType) As String
Note that the types that I'm overloading (ArrayOfDecimalArraysType, ThreeDimensionalDecimalArrayType) are not classes that inherit from the same base class. They are different structures that don't inherit from anything. They were written by someone else and I can't change them.
When I call it from within the same class like this
Dim MyThreeDimensionalDecimalArrayType As ThreeDimensionalDecimalArrayType
RenderRateTable(MyArrayIndexes, CType(MyThreeDimensionalDecimalArrayType, Object))
it doesn't go to the right method. It just goes to RenderRateTable().
What's even stranger is, the call is made with two arguments (parameters), but these are (ignored?) and it calls a method that takes no parameters and no run-time error is thrown!
I have Option Strict Off and the variable I'm passing to the parameter ThreeDimensionalArray is of type Object.
I'm trying to get it to where I have a bunch of overloads and it picks the right method based on the type of the Object passed.
Polymorphic method calling instead of an Select Case statement. I hate conditional blocks like that.
UPDATE
I got the code working by declaring the overloads Public, but I still don't understand:
Why the dispatcher wouldn't find the right Private method when the
call is within the same class.
Why the dispatcher would call a method with no parameters when the call is made with 2 parameters, and not throw an error.
You have RenderRateTable() as Public and the rest as Private, which will prevent it from being able to use the correct overload when called from outside the class.
It is very likely that Option Strict On would have pointed out that as a problem: I recommend that you use it to make your programming endeavours easier :)

Understanding Array.ConvertAll, can I DirectCast?

I have a base class, DtaRow, that has an internal array of Strings containing data. I have dozens of subclasses of DtaRow, like UnitRow and AccountRow, who's only purpose is to provide Properties to retrieve the values, so you can do aUnit.Name instead of aUnit.pFields(3).
I also have a DtaTable object that contains a Friend pRows As New Dictionary(Of Integer, DtaRow). I don't generally insert DtaRows into the DtaTable, I insert the subclasses like UnitRows and AccountRows. Any given table has only one type in it.
Over in the main part of the app I have an accessor:
Public Readonly Property Units() As IEnumerable
Get
Return Tables(5).pRows.Values 'oh oh oh oh table 5, table 5...
End Get
End Property
This, obviously, returns a list of DtaRows, not UnitRows, which means I can't do MyDB.Units(5).Name, which is the ultimate goal.
The obvious solution is to Dim ret As New UnitRow() and DirectCast everything into it, but then I'm building thousands of new arrays all the time. Uggg. Alternately I could put DirectCast everywhere I pull out a value, also uggg.
I see there is a method called Array.ConvertAll that looks like it might be what I want. But maybe that just does the loop for me and doesn't really save anything? And if this is what I want, I don't really understand how to use DirectCast in it.
Hopefully I'm just missing some other bit of API that does what I want, but failing that, what's the best solution here? I suspect I need...
to make a widening conversion in each DtaRow subclass?
or something in DtaTable that does the same?
You can use ConvertAll to convert an array into a different type.
Dim arr(2) As A
Dim arr2() As B
arr(0) = New B
arr(1) = New B
arr(2) = New B
arr2 = Array.ConvertAll(arr, Function(o) DirectCast(o, B))
Class A
End Class
Class B
Inherits A
End Class
In your case, I think it would look like this
Return Array.ConvertAll(Tables(5).pRows.Values, Function(o) DirectCast(o, UnitRow))
Note that this will create a new array each time.
You can cast the objects into a list(Of String) based on the field you want.
Return Tables(5).pRows.Values.Cast(Of DtaRow).Select(Function(r) r.name).ToList
YES! I went non-linear. This only works because of OOP...
My ultimate goal was to return objects from the collection as a particular type, because I knew I put that type in there in the first place. Sure, I could get the value out of the collection and CType it, but that's fugly - although in C# I would have been perfectly happy because the syntax is nicer.
So wait... the method that retrieves the row from the collection is in the collection class, not the various subclasses of DtaRow. So here is what I did...
Public ReadOnly Property Units() As IEnumerable
Get
Return Tables(dbTblUnits).pRow.Values
End Get
End Property
Public ReadOnly Property Units(ByVal K as Integer) As UnitRow
Get
Return DirectCast(Tables(dbTblUnits)(K), UnitRow)
End Get
End Property
Public ReadOnly Property Units(ByVal K as String) As UnitRow
Get
Return DirectCast(Tables(dbTblUnits).Rows(K), UnitRow)
End Get
End Property
Why does this solve the problem? Well normally if one does...
Dim U as UnitRow = MyDB.Units(K)
It would call the first method (which is all I had originally) which would return the .Values from the Dictionary, and then the Default Property would be called to return .Item(K). But because of the way the method dispatcher works, if I provide a more specific version that more closely matches the parameters, it will call that. So I provide overrides that are peers to the subclasses that do the cast.
Now this isn't perfect, because if I just call Units to get the entire list, when I pull rows out of it I'll still have to cast them. But people expect that, so this is perfectly acceptable in this case. Better yet, when I open this DLL in VBA, only the first of these methods is visible, which returns the entire collection, which means that Units(k) will call the Default Property on the DtaTable, returning a DtaRow, but that's fine in VBA.
OOP to the rescue!

How do I determine if a value is an instance of a generic type, ignoring the type parameter, in vb.net?

I have a class C(Of T). I want to determine if some given value has type C, regardless of what T is. For example, I might want to determine if a value is a strongly-typed list, regardless what type of items the list stores.
I just need to know how to do it in VB.net. In Java the syntax is like this:
var result = obj instanceof Gen2<?>;
I believe a compact solution for your problem would be:
Dim result = (obj.GetType().GetGenericTypeDefinition().Equals(GetType(Gen2(Of ))))
Explanation:
Gets the Type object representing the base type of instance obj
Gets the generic type underlying the compiler instance type.
Gets the generic type of Gen2 without a qualifying parameter.
Compares the two generics to see if they are equal and returns the result.
It's not nearly as compact as the Java solution you posted (unless I'm mistaken, C# doesn't support either the instanceof keyword or the Java generic wildcard syntax), but it will work.
Edit: Prompted by Cory Larson's comment below, I should add that while the method I posted only works for directly comparing the generic to a known generic type, if you want to find out if it implements a generic interface, use:
Dim result = (obj.GetType().GetGenericTypeDefinition().GetInterface(GetType(IMyGeneric(Of )).FullName) IsNot Nothing)
Sure, sort of. For example:
Dim obj As IList(Of Double) = New List(Of Double)
Dim result As Boolean = obj.GetType().IsGenericType AndAlso _
obj.GetType().GetGenericTypeDefinition().Equals(GetType(IList(Of )))
For that, the result is False. If you change the comparison from IList(Of ) to just List(Of ), then it works.
Dim obj As IList(Of Double) = New List(Of Double)
Dim result As Boolean = obj.GetType().IsGenericType AndAlso _
obj.GetType().GetGenericTypeDefinition().Equals(GetType(List(Of )))
Will return True.
EDIT: Dang, Dan Story got it first.
If you are seeking to find out whether a type is a Foo(Of T) because you're interested in using some property which does not depend upon T, I would suggest that you should make that property available in either a non-generic base class or a non-generic interface. For example, if defining an ISuperCollection(Of T) which provides array-like access, one could offer a non-generic ISuperCollection collection which implements methods Count, RemoveAt, CompareAt, SwapAt, and RotateAt (calling RotateAt(4,3,1) would rotate three items, starting at item 4, up one spot, thus replacing item 5 with 4, 6 with 5, and 4 with the old value of 6), and have ISuperCollection(Of T) inherit from that.
BTW, if you segregate reader interfaces from writer interfaces, the reader interfaces can be covariant and the writer interfaces contravariant. If any property or indexer implements both read- and write- functions, you'll need to define a read-write interface which includes read-write implementations of any such property or indexer; a slight nuisance, but IMHO worth the small additional effort.