0

I am aware that similar questions have been asked before:

But my issue is not addressed there. In C# I can write this:

return myFoo ??= new Foo() 

If myFoo is null, this line will create a new Foo, assign it to myFoo, and return the value of myFoo.

I want to translate this to VB. I can do it in two statements e.g.:

If myFoo Is Nothing Then myFoo = New Foo()
Return myFoo

or even using the two-argument If function:

myFoo = If(myFoo, New Foo())
Return myFoo

I would prefer to do it in one statement. This looks like it ought to be equivalent to the C# version:

Return myFoo = If(myFoo, New Foo())

But it doesn't work because it interprets the = as a comparator, not an assignment.

Is there an elegant solution?

Richard Pawson
  • 1,494
  • 1
  • 10
  • 15
  • I'm no VB expert, but I don't think it has a null-coalescing assignment operator like C# does. – DavidG Jan 18 '22 at 13:22
  • It's simply not possible to do it in a single line in VB. In C#, assignments effectively return the value that was assigned but that's not the case in VB. This is basically the same situation as trying to translate something like `if (boolVar = boolValue)`. That can't be done in VB and neither can what you want. You have to use two separate lines. –  Jan 18 '22 at 13:26
  • 3
    I'm also wondering what's the use case where you need this. You're returning that object out of this function anyway. `Return If(myFoo, New Foo())` should be sufficient, no? – msmolcic Jan 18 '22 at 13:27
  • 1
    @msmolcic It's often used with caching. The method gets a (cached) `Foo`, creating it first and storing it in the cache if appropriate – canton7 Jan 18 '22 at 13:28
  • Is `myFoo` a local or a global variable? – GSerg Jan 18 '22 at 13:29
  • @canton7 I see what you're saying, right. I'm usually prefixing my class fields with an underscore so I thought `myFoo` is either a function parameter or variable created within a function itself. – msmolcic Jan 18 '22 at 13:31
  • 7
    The major difference here is that VB has an [Assignment Statement](https://learn.microsoft.com/en-us/dotnet/visual-basic/reference/language-specification/statements#assignment-statements) whereas C# has an assignment *expression*. The difference between the two is that expressions produce values, statements do not. – Damien_The_Unbeliever Jan 18 '22 at 13:32
  • 2
    `I would prefer to do it in one line` - well, `myFoo = If(myFoo, New Foo()) : Return myFoo` is one line... – GSerg Jan 18 '22 at 13:33
  • You could get close if you wrote your own version of `If` that returned the value and assigned it using `ByRef`, but that's a horrible hack and probably has other issues. – DavidG Jan 18 '22 at 13:35
  • @GSerg. My sloppiness, I meant 'one statement', not 'one line'. – Richard Pawson Jan 18 '22 at 13:49
  • @canton7 if you want to cache, `Lazy(Of T)` provides that functionality. Then just return the `Value` member and it will run the factory function if needed. – Craig Jan 18 '22 at 14:58
  • 1
    @Craig It requires an extra few object allocations, and a bunch of additional cost (in order to be properly thread-safe) which isn't necessary if you're just doing something lightweight and single-threaded. I mean if `Foo` is reasonably cheap, you gain nothing by substituting the creation of the `Foo` with the creation of a `Lazy` instead – canton7 Jan 18 '22 at 15:05
  • 1
    @Damien_The_Unbeliever: This is the crux of the issue - you should write it up as the answer. – Dave Doknjas Jan 18 '22 at 15:52
  • 1
    @RichardPawson - "I would prefer to do it in one statement. " Why? – dbasnett Jan 18 '22 at 16:40
  • @dbasnett. It's vaguely annoying that one statement in C# has to be two in VB, but it's no great problem to have to use two statements, I just wondered if there was a more elegant way to code it. The habit of defining all functions as a single expression comes from functional programming, but - before anyone else points it out - caching myFoo is not permissible in functional programming anyway! – Richard Pawson Jan 18 '22 at 17:26

1 Answers1

2

C-heritage languages (which includes C#) have historically treated assignment as an expression which means that it has a result. Historically, that result is the value that was assigned. This has advantages, which includes allowing more concise multiple assignments and testing results of assignment in conditionals. It also has disadvantages, which include potential confusion of assignment and equality operators in conditionals.

Other languages treat assignment as a statement which means that it does not have a result and cannot be composed into another operation. VB is one of these languages (others include Fortran and Pascal).

Because assignment is a statement in VB, you cannot assign and test in the same operation unless you write your own function to do so. You will have to do your two-line operation, or use the : statement separator to put both statements on one line.

Idle curiosity on VB that relates to language families: pre-.NET, VB had much more in common with Fortran than C. The end block statements follow the same conventions as Fortran, the code editor will recognize EndIf and convert it to End If, the array layout was the same (column-major instead of row-major), and the code editor would recognize the Fortran convention for a double-precision constant e.g. 1.0d0 would be treated as a double 1.0. The last two have been lost with the move to .NET.

Craig
  • 2,248
  • 1
  • 19
  • 23