7

We have a VB.NET project which I am doing some refactoring in. A lot of current functions require a userId to be passed in as a parameter. For example:

Private Function Foo(userId As Integer) As String
    Return "Foo"
End Function

But now, I have made this userId paramater no longer needed in much of our code.

I was thinking I would just remove all the userId parameters from all of the functions that don't need them anymore, and try re-building the project to see what calling code needs to change. To my surprise though, the code built successfully.

I learned that you can call a function which returns a string and doesn't take any parameters, but still pass in an Integer value. VB.NET builds/executes this code as if you were trying to invoke the function and then get the character from the String at the specified index. For example:

Imports System

Public Module MyModule
    Private Function Foo() As String
        Return "Foo"
    End Function

    Public Sub Main()
        Console.WriteLine(Foo(0)) ' prints 'F'
        Console.WriteLine(Foo(1)) ' prints 'o'
    End Sub
End Module

(.NET Fiddle)

I want my build to fail in this case. I have tried using Option Strict On and Option Explicit On but neither seem to change this behaviour.

Is there anyway to make this kind of function invocation invalid in my VB.NET project?

Jesse Webb
  • 43,135
  • 27
  • 106
  • 143
  • 6
    The 'problem' is that VB uses parens for array indexing (a string is a char array) *and* for method parameters. c# would catch it because it uses `[]` for indexers and would know the `(0)` is for a non existent arg. Its built in, basic language functionality, so you cant force it not to not allow it – Ňɏssa Pøngjǣrdenlarp Jan 11 '18 at 19:38
  • I found [a related Q&A](https://stackoverflow.com/q/142697/346561) where a user got burned by this language "feature". But unfortunately, it doesn't say if it is possible to disable support for this feature. – Jesse Webb Jan 11 '18 at 19:41
  • c# allows string indexing as well - the problem is the syntax/symbology in VB that uses `()` for two quite different things. – Ňɏssa Pøngjǣrdenlarp Jan 11 '18 at 19:47
  • @Plutonix Thanks for the info, it seems you are correct that it is not possible to disable this behavior in the VB.NET compiler. Feel free to post that as an answer and I will gladly accept it (while angrily shaking my fist at the VB language). – Jesse Webb Jan 11 '18 at 19:50
  • It seems this is only a problem because VB.NET doesn't require parentheses when invoking parameter-less functions. I searched to see if it was possible to disable that feature, and [it isn't possible according to this other Q&A](https://stackoverflow.com/q/1298605/346561). – Jesse Webb Jan 11 '18 at 19:52
  • You code is equivalent to this one: `Option Strict On Imports System Public Module MyModule Private Function Foo() As String Foo = "Foo" End Function Public Sub Main() Console.WriteLine(Foo) ' prints 'F' Console.WriteLine(Foo(1)) ' prints 'o' End Sub End Module` – Hackerman Jan 11 '18 at 19:52
  • That's why Visual Basic takes `Console.WriteLine(Foo(1))` as the result of the function(1) -> F – Hackerman Jan 11 '18 at 19:53
  • yes, thats an aspect too: c# would require method parens so it would be `Foo()[0]` to get the first char - you have to be explicit about it. VB doesnt require them but would recognize `Foo()(0)` as the first letter. But since method parens are optional, you are toast – Ňɏssa Pøngjǣrdenlarp Jan 11 '18 at 19:55
  • I don't remember offhand if VB returns a `Char` or a `String` from indexing a string; if it's the former, then this is a spot where explicit type declaration on variables can help you, because you might get errors when an attempt is made to assign a char to a string. – Craig Jan 11 '18 at 21:42

1 Answers1

4

Create an overload with no parameters which is a copy of the original function in every other respect.

Public Function Foo() As String
    Return "Foo"
End Function

Now change the type of userId to something else (not Object or anything numeric etc.)

Public Function Foo(userId As DateTime) As String
    Return "Foo"
End Function

Since there is an overload with a parameter, the compiler thinks you mean to call that, instead of indexing the chararray. So you have compile errors. Fix the errors

Then delete the original function.

djv
  • 15,168
  • 7
  • 48
  • 72