twinbasic / lang-design

Language Design for twinBASIC
MIT License
11 stars 1 forks source link

Functions Return Multiple Values #14

Open kismert opened 3 years ago

kismert commented 3 years ago

(edited) - I took input from @WaynePhillipsEA and @KDGundermann, and updated my proposal to use Tuples, similar to VB.NET It happened again - I worked myself into a coding corner, and found myself pining for functions that can return multiple values:

Function DoStuff() As (Stuff1 As String, Stuff2 As Variant)
  Return ("abc", Null)
End Function

Calling would look like:

(Val1, Val2) = DoStuff()
' or VB.NET style:
Result = DoStuff() : Debug.Print Result.Stuff1, Result.Stuff2

This tuple return style would complement Out parameters. While I acknowledge that Out is good and needed, I intensely dislike the 'modify by reference' style of returning values.

vbRichClient commented 3 years ago

Since VB6/VBA supports the returning of Structs (UDTs) already, I can't really see the advantage of introducing more reasons which might throw off the parser/debugger.

Also, the existing ByRef-mechanism allows for much less code (looking at your example). At the call-site it would look this way: DoStuff Ret1, Ret2

At the side of the routine-definition one will save a lot of typing: Sub DoStuff(Val1 As String, Val2 As Variant)

Just this single line of routine-signature is equivalent to your Function DoStuff-def.

Olaf

WaynePhillipsEA commented 3 years ago

I'm not against the idea in principle, but would prefer to implement something along the lines of Tuples (see https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/data-types/tuples).

vbRichClient commented 3 years ago

As for Tuples (.NET-style) - the first (unnamed form) is easy to do via the Array-Function.

Function ReturnTuple()
  'return a Date, a String and a Boolean
  return Array(Now, "Some String", True)
End Function

The second (named) form is quite straight forward as well, via e.g. JSON-notation (here using RC6), but a normal VB-Collection would do fine here as well:

Function ReturnTuple() As cCollection
  'return a Date, a String and a Boolean
  Set ReturnTuple = New_c.JSONObject
      ReturnTuple.Prop("aDate") = Now
      ReturnTuple.Prop("aString") = "SomeString"
      ReturnTuple.Prop("aBoolean") = True
End Function

at the call-site:

With ReturnTuple
  Debug.Print TypeName(!aDate), TypeName(!aString), TypeName(!aBoolean)
End With

So, from my point of view, we have enough support at language-level (or at lib-level) already.

Olaf
WaynePhillipsEA commented 3 years ago

@vbRichClient my counter argument in support of tuples would be for the type safety, rather than everything being thrown around as Variants. With tuples you're essentially passing around a UDT with strict types and getting a small performance advantage over the arrays/collection. This is certainly not high-priority; just something to consider in the future.

kismert commented 3 years ago

@vbRichClient my counter argument in support of tuples would be for the type safety, rather than everything being thrown around as Variants. With tuples you're essentially passing around a UDT with strict types and getting a small performance advantage over the arrays/collection. This is certainly not high-priority; just something to consider in the future.

@WaynePhillipsEA tuples are a good solution to the multiple return problem.

kismert commented 3 years ago

Since VB6/VBA supports the returning of Structs (UDTs) already, I can't really see the advantage of introducing more reasons which might throw off the parser/debugger.

Also, the existing ByRef-mechanism allows for much less code (looking at your example). At the call-site it would look this way: DoStuff Ret1, Ret2

At the side of the routine-definition one will save a lot of typing: Sub DoStuff(Val1 As String, Val2 As Variant)

Just this single line of routine-signature is equivalent to your Function DoStuff-def.

Olaf

@vbRichClient I use UDTs for this purpose, too, but in VBx, you can't make an object a member of a UDT, and you can't pass a UDT to a variant parameter. Maybe tB will fix these limitations. Plus, you have to name and define UDTs -- for me, too much clutter for just returning values. Like others, I prefer a more functional style of programming, and modify-by-reference runs counter to the functional idea of immutable parameters.

KDGundermann commented 3 years ago

when returning multiple values, these values usually have something in common. And Function DoStuff() As String, Variant tells me nothing about what is this String and Variant ?? I usually create a small class with some public properties, give those properties a good name and return an instance of this class.

Function DoStuff() As clsReturnValues

kismert commented 3 years ago

@KDGundermann

And Function DoStuff() As String, Variant tells me nothing about what is this String and Variant ??

Yes, a flaw in my proposed definition. Perhaps: Function DoStuff() As (Stuff1 As String, Stuff2 As Variant)

I usually create a small class with some public properties, give those properties a good name and return an instance of this class.

Function DoStuff() As clsReturnValues

This is a much more viable idea in tB, where you can define many classes in the same file. However, tuples would keep the whole definition within the function.