15

I know there's no straightforward way for multiple assignment of function in VB, but there's my solution - is it good, how would you do it better?

What I need (how would I do it in python, just an example)

def foo(a)    ' function with multiple output
    return int(a), int(a)+1

FloorOfA, CeilOfA = foo(a) 'now the assignment of results

How I do it in VB:

Public Function foo(ByVal nA As Integer) As Integer() ' function with multiple output
    Return {CInt(nA),CInt(nA)+1}
End Function

Dim Output As Integer() = foo(nA) 'now the assignment of results
Dim FloorOfA As Integer = Output(0)
Dim CeilOfA As Integer = Output(1)
Cœur
  • 37,241
  • 25
  • 195
  • 267

4 Answers4

18

For future readers, VB.NET 2017 and above now supports value tuples as a language feature. You declare your function as follows:

Function ColorToHSV(clr As System.Drawing.Color) As (hue As Double, saturation As Double, value As Double)
  Dim max As Integer = Math.Max(clr.R, Math.Max(clr.G, clr.B))
  Dim min As Integer = Math.Min(clr.R, Math.Min(clr.G, clr.B))

  Dim h = clr.GetHue()
  Dim s = If((max = 0), 0, 1.0 - (1.0 * min / max))
  Dim v = max / 255.0

  Return (h, s, v)
End Function

And you call it like this:

Dim MyHSVColor = ColorToHSV(clr)
MsgBox(MyHSVColor.hue)

Note how VB.NET creates public property named hue inferred from the return type of the called function. Intellisense too works properly for these members.

Note however that you need to target .NET Framework 4.7 for this to work. Alternately you can install System.ValueTuple (available as NuGet package) in your project to take advantage of this feature.

dotNET
  • 33,414
  • 24
  • 162
  • 251
9

Your solution works and it is an elegant way to return multiple results, however you could also try with this

Public Sub foo2(ByVal nA As Integer, ByRef a1 As Integer, ByRef a2 As Integer) 
    a1 = Convert.ToInt32(nA)
    a2 = Convert.ToInt32(nA) +1
End Sub

and call with

foo2(nA, CeilOfA, FloorOfA)    

If you have many results to return it is logical to think to a class that could return all the values required (Expecially if these values are of different dataTypes)

Public Class CalcParams
   Public p1 As Integer
   Public p2 As String
   Public p3 As DateTime
   Public p4 As List(Of String)
End Class

Public Function foo2(ByVal nA As Integer) As CalcParams
    Dim cp = new CalcParams()
    cp.p1 = Convert.ToInt32(nA)
    .......
    Return cp
End Function
LBPLC
  • 1,570
  • 3
  • 27
  • 51
Steve
  • 213,761
  • 22
  • 232
  • 286
  • and for such a basic use is it really needed to instantiate a class? Maybe `structure` is enough? – Intelligent-Infrastructure May 08 '13 at 10:16
  • It is not so much different than returning an array. But you are right, with only two parameters and of integer type you could go with your solution or passing the expected results By Ref. The things get more complicated when you need to deal with complex data. It was just an example (I admit, a bit unlikely) – Steve May 08 '13 at 10:21
  • Yes also a structure will work well. You will gain something but it really depends on how many times you call this method. – Steve May 08 '13 at 10:35
3

The methodology you are using is a good one, by the way, you can pass the required variable as a reference to your subroutine inorder to make your code more cleaner.

Dim FloorOfA As Integer
Dim CeilOfA As Integer

Call foo(10.5, FloorOfA, CeilOfA)

Public Sub foo(ByVal xVal As Integer, ByRef x As Integer, ByRef y As Integer)
    x = CInt(xVal)
    y = CInt(xVal) + 1
End Sub
Rajaprabhu Aravindasamy
  • 66,513
  • 17
  • 101
  • 130
3

Maybe you can use Tuple:

Public Function foo(ByVal nA As Integer) As Tuple(Of Integer,Integer) ' function with multiple output
    Return Tuple.Create(CInt(nA),CInt(nA)+1)
End Function

Dim FloorOfA, CeilOfA As Integer
With foo(nA) 'now the assignment of results
   FloorOfA =.item1
   CeilOfA = .item2
End With

Edit: New Tuple replace by Tuple.Create (thanks to @mbomb007)

IvanH
  • 5,039
  • 14
  • 60
  • 81
  • I don't like it somehow... tuple seems to be heavy, and I just need two integers. + how many times subroutine foo is called within the `with`, one or two? – Intelligent-Infrastructure May 08 '13 at 10:14
  • @Intelligent-Infrastructure: The subroutine is called only once. 'With' replaces 'Output' declaration. Tuples allow to avoid byref parameters which are not considered to be very good practice. You can use .item1, .item2 in your agorithm and thus avoid FloorOfA,CeilOfA declaration. – IvanH May 08 '13 at 11:07
  • I like the use of Tuple, but I wouldn't use "With" here. Adds a level of nesting, merely to access multiple return results. I would assign the result to a local var. `Dim Output = foo(nA) / Dim FloorOfA = Output.Item1`. Like code in question, but using Tuple rather than array. – ToolmakerSteve Dec 09 '13 at 22:02
  • @ToolmakerSteve: "With" is used to avoid necessity of variable declaration. Especially in case if option infer is not used and full declaration `Dim Output as Tuple(Of Integer,Integer)= foo(nA)` is necessary. I admit that it is a matter of personal taste. – IvanH Dec 10 '13 at 10:26
  • 1
    @IvanH That's what `Tuple.Create()` is for, so you don't have to use such a lengthy declaration. Use that instead. – mbomb007 Sep 06 '17 at 18:32
  • @mbomb007 You mean replace Return new Tuple(Of Integer,Integer) (CInt(nA),CInt(nA)+1) with Return Tuple.Create(CInt(nA),CInt(nA)+1). THX I did not know that. – IvanH Sep 20 '17 at 14:00
  • @IvanH Yeah. Also, why is `CInt` called? `nA` is already an Integer, so that shouldn't be needed. – mbomb007 Sep 20 '17 at 15:27
  • @mbomb007 Because it is used in the questition. I took it like an example of tranformation. – IvanH Oct 23 '17 at 11:44