I suggest you ...

Allow multiple variable names with single type specifier in functin call

This suggestion is migrated to Developer Community. Please use below link to view the current status.
https://developercommunity.visualstudio.com/content/idea/351209/allow-multiple-variable-names-with-single-type-spe.html
Current:
Public Function DoSomething(x As Integer, y As Integer, w As Integer, h As Integer, Value As Integer, Name As String, Count As Integer) As Boolean

Propsed:
Public Function DoSomething(x, y, w, h, Value As Integer, Name As String, Count As Integer) As Boolean

All variables x, y, w, h, Value would be of type Integer, like in Dim statement.

330 votes
Vote
Sign in
(thinking…)
Sign in with: facebook google
Signed in as (Sign out)
You have left! (?) (thinking…)
PavlinII shared this idea  ·   ·  Flag idea as inappropriate…  ·  Admin →

28 comments

Sign in
(thinking…)
Sign in with: facebook google
Signed in as (Sign out)
Submitting...
  • PavlinII commented  ·   ·  Flag as inappropriate

    @RJP This suggestion was already mentioned here. I've replied:

    > Last line of my comment from October 27, 2011:
    >
    >> - I could use VB6 notations using %, @, ! and other special characters, but it does not meet my request for easily readable code.

  • RJP commented  ·   ·  Flag as inappropriate

    Here's a less verbose declaration syntax that's already legal in VB...
    Function DoSomething(x%, y%, w%, h%, Value%, Name$, Count%) As Boolean

    (Note: Public is the default scope - it doesn't need to be specified.)

    Unfortunately there's no type character for Boolean, but if DoSomething needed to return an integer, we could declare it as
    Function DoSomething%(x%, y%, w%, h%, Value%, Name$, Count%)

  • dhsfjkhadks commented  ·   ·  Flag as inappropriate

    It would be nice if VB would allow declaration syntax like C, (int i, j, k). It is consistent with the keyword format of the language and it would address a weakness. VB needs to improve and evolve or get left behind.

  • hfahdl commented  ·   ·  Flag as inappropriate

    VB declaration syntax is too verbose. The example given:

    Public Function DoSomething(x As Integer, y As Integer, w As Integer, h As Integer, value As Integer, name As String) As Boolean

    can be expressed as:

    bool DoSomething(int x,y,w,h,value, string name)

  • HMan commented  ·   ·  Flag as inappropriate

    I'm just saying, even without arrays there are plenty of safe ways to handle this, without potentially breaking existing code just for the sake of saving 6 characters typed. It's not a bad suggestion, but I fear it would bring more confusion and code breakage than anything useful. Intellisense already types most of the characters you would potentially save for you anyways.

  • PavlinII commented  ·   ·  Flag as inappropriate

    Hi HMan2828,
    suggested update need to consider current settings of Option Explicit, Option Strict and Option Infer.
    I expect no effect of this suggestion to old or bad code using Variant with Option Explicit Off, Option Strict Off, Option Infer Off.

    And I expect this suggestion will work just fine with optimal* configuration:
    Option Explicit On
    Option Strict On
    Option Infer Off

    Desicition about Option Infer On situation is on development team.

    Array alternative is a bad idea for several reasons:
    - DoSomething({x, y, w}, Value, Name, Count) - compiler can not check argument count
    - DoSomething({x, y, w, h, Value, Count, Gimme, Gimme, Gimme}, value, Name, Count)
    - New Rectangle(xywh(0), xywh(1), xywh(2), xywh(3)) instead of New Rectangle(x, y, w, h)

    And I believe you woudn't appreciate such overload in 3rd party component nor .NET framework itself.

    *Optimality of this combination is my personal preference based od subjective opinion. Please, do not argue about it.

  • HMan commented  ·   ·  Flag as inappropriate

    Besides, you kind of already have the solution:

    Public Function DoSomething(ByVal xywh() As Integer, Value As Integer, Name As String, Count As Integer)

    DoSomething({x, y, w, h}, value, name, count)

  • HMan commented  ·   ·  Flag as inappropriate

    Wouldn't that break existing code that might be (probably wrongly, but still...) relying on type inference? Right now the behavior is that in the OP's example x,y,w,h would all be of type Object and ByVal. How do you suggest this change in syntax would keep compatibility with existing code?

  • Anthony D. Green [MSFT] commented  ·   ·  Flag as inappropriate

    Hi again, PavlinII,

    Thanks for all that feedback!

    Here's the reason we're considering Output at the callsite - it would allow us to infer a variable declaration inline. Today because you need to declare the variable before hand you also need to specify its type explicitly and can't use type-inference. A lot of users, myself included, love type inference and this limitation creates an inconsistent experience. With an explicit Output keyword at the call site instead of typing this:

    Dim result As Integer ' No type inference here.
    If Integer.TryParse(stringVariable, result) Then ...

    You could type:

    If Integer.TryParse(stringVariable, Output result) Then ' With type of variable inferred.
    or
    If Integer.TryParse(stringVariable, Output result As Integer) Then ' With type of variable explicit.

    Technically we could still do this without the Output keyword but it's a little harder to predict and see.

    But, even if we did add this feature we'd need to still support doing it the way you do today for back-compat reasons.

    Regards,

    -ADG

  • PavlinII commented  ·   ·  Flag as inappropriate

    2b) Ok, I needed to submit the answer to see what I'm missing :)

    Output keyword on declaration side may be used in any parameter. As ByRef. This is useful.
    So Output keyword should be written to every occurence on caller side.
    exitCode = Execute("cmd.exe", stdIn, Output stdOut, Output stdErr)

    Question is: Do you really need to specify Output keyword on caller side?
    Let's say it's ByRef call.
    Dim S As Stream = Nothing
    Ret = TryParse(S)
    I do not need (nor have to) specify anything.

    Let's say it's ByRef call without initialization.
    Dim S As Stream
    Ret = TryParse(S)
    Little annoying (but useful) warning is generated.

    Let's say it's Output call.
    Dim S As Stream
    Ret = TryParse(S)
    This is OK for me. Compiler recognises Output parameters. VB programmer does not need to see the "Output" keyword. It just does not generate that warning. C-like language programmer would tear his hair and evacuating this planet.

  • PavlinII commented  ·   ·  Flag as inappropriate

    Hello Anthony,
    thank you for reviewving this suggestion.

    1) I prefer version a). It's consistent with other rules and therefore intuitive.
    It might be usefull to be able to specify several different modifiers. But when you do so, you have to write modifier to every parameter of that sequence.

    Sub M(ByRef a, b, c, d As Integer) - version a), legal, all variables are ByRef
    Sub M(ByRef a, ByRef b, ByVal c, ByRef d As Integer) - extended, legal, every variable is described individually
    Sub M(ByRef a, ByRef b, ByRef c, ByRef d As Integer) - legal, but not smart
    Sub M(a, ByRef b, c, d As Integer) - illegal
    Sub M(a, b, c, ByRef d As Integer) - illegal
    Sub M(ByRef a, ByRef b, c, d As Integer) - illegal
    Sub M(ByRef a, b, c, ByVal d As Integer) - illegal

    2a) I do like this idea with prefix, root, suffix and Min to be Optional:
    Sub M(Mandatory As String, Optional prefix, root, suffix As String, Min As Integer)
    With rule: Everything behind single "Optional" keyword is optional.

    Optional have to specify default value:
    Sub M(Mandatory As String, Optional prefix, root, suffix As String = Nothing, Min As Integer = 0)

    Question is: What if you need different default values?
    Sub M(Mandatory As String, Optional prefix = "http://", root = "/", suffix As String = Nothing, Min As Integer = 0)
    I would consider this illegal. I do not like irregularity of '=' position.
    This should be written in long way, with single "Optional" keyword. Or optionally with many "Optional" for backward compatibility.
    Sub M(Mandatory As String, Optional prefix As String = "http://", root As String = "/", suffix As String = Nothing, Min As Integer = 0)

    I would consider illegal to specify Optional in the middle of sequence.
    Sub M(Mandatory, prefix, Optional root, suffix As String = Nothing)
    It shoudl be written like this:
    Sub M(Mandatory, prefix As String, Optional root, suffix As String = Nothing)

    I do not like out of order optional parameters where "root" is NOT optional.
    Sub M(Optional prefix, root, Optional suffix)
    This would make the code more difficult to read. It also may lead to ambigous parameter value assigning situations. You can use different overload to solve this situation.

    Same rule as 1) can be used:
    Single Optional keyword => everything behind is optional.
    Multiple Optional keywords => you have to specify Optional keyword from it's first occurence to the last parameter (like today).

    2b) I consider "Output" keyword to be similar to "ByRef" keyword. Not to "Optional" keyword.
    And all ByRef-ByVal rules can be applied to ByRef-ByVal-Output trio.
    This seems simple, short coded, non breaking and powerfull enough and to me.

    Am I missing something?

  • Anthony D. Green [MSFT] commented  ·   ·  Flag as inappropriate

    Hi PavlinII,

    Thanks for the suggestion. We thought pretty long and hard about this suggestion and can totally see the pros - particularly in scenarios where being concise is at a premium (like in lambdas), or where duplicate types are very common - user-defined binary operators. There is definitely precedent in the language for what this means. It also raises some interesting questions:

    1) Modifiers/Attributes:
    a) They distribute over the chain:

    ' x and y are integers, both are ByRef.
    Sub M(ByRef x, y As Integer)

    b) They don't distribute:

    ' x and y are integers, only x is ByRef.
    Sub M(ByRef x, y As Integer)

    c) They break the chain:

    ' This is illegal. x has a modifier and must also declare a type explicitly to avoid ambiguity.
    Sub M(ByRef x, y As Integer)

    The existing rules today around modifiers/attributes on fields would suggest we'd go with (a) for this.

    2) Intersection with possible (though not necessarily planned) future features:
    a) What if we let you declare Optional parameters out of order?

    ' These are all optional.
    Sub M(Optional prefix, root, suffix As String)

    But let's say you wanted only the first and last to be optional (yes, this scenario has come up) you could declare it like this:

    Sub M(Optional prefix As String, root As String, Optional suffix As String)

    Which might be fine and is probably clearer. But VB also supports a rapid-prototyping typeless style and you couldn't write this:

    Sub M(Optional prefix, root, Optional suffix)

    In fact in this mode you wouldn't be able to use any modifier without impacting any subsequent parameters in typeless mode. OK, so maybe we decide it either doesn't work in typeless mode or you're just forced to explicitly type out a type in this case.

    b) Let's say we added Output parameters to VB. C# already supports them and they're a pretty common pattern in .NET for multiple return values and the TryXyz pattern (e.g. TryParse, Dictionary.TryGetValue)

    Function Execute(path As String,
    stdIn As Stream,
    Output stdOut, stdErr As Stream
    ) As Integer

    This has the same problem as with Optionals - it's already possible today in C# to declare output parameters in any order. But like before we can require explicit typing in that edge case. Now let's look at the caller side:

    exitCode = Execute("cmd.exe", stdIn, Output stdOut, stdErr)

    Again the question of whether to distribute or not is a problem. If we don't support it you need to repeat the modifier:

    exitCode = Execute("cmd.exe", stdIn, Output stdOut, Output stdErr)

    It's odd that the use site doesn't follow the same rules as declaration, but maybe we can live with it.

    If we don't support it then the original code works but now it's impossible for an Output parameter to precede any non-Output parameters:

    M(Output x, y, Output z)

    Maybe we work around this too by letting you force ByVal and ByRef on the middle argument where it's ambiguous?

    M(Output x, ByVal y, Output z)

    This is probably rare enough that this escape hatch is good, especially for output parameters. The case may not be so cut and dry for ByRef arguments. Now arguably when the argument passing mode changes mid argument list it's probably good to be more explicit but it does mean any translation from C# code would have to potentially know that but we could flag it with a warning or something.

    Now, I'm not saying we're going to do any of these language features but it is important when deciding on any one how it might intersect with a future whole.

    What do you guys think? Do any of these possible worlds sound confusing or make you think the feature is less desirable?

    -Anthony D. Green, Program Manager, Visual Basic & C# Languages Team

  • Anonymous commented  ·   ·  Flag as inappropriate

    @PavlinII : Yeah I Agree with you, it's make uneasy to read when the lines meet upper than 10000 line code. When I create a long parameters for function for example 12 / 13 parameters, I create a structure or class, but if your suggest was available in next release vs, it's useful .. ;-)

  • PavlinII commented  ·   ·  Flag as inappropriate

    Anonymous: Last line of my comment from October 27, 2011:

    > - I could use VB6 notations using %, @, ! and other special characters, but it does not meet my request for easily readable code.

  • Anonymous commented  ·   ·  Flag as inappropriate

    Public Function DoSomething(x%, y%, w%, h%, value%, name$, count%) As Boolean
    Return True
    End Function

    It's more simple and ready to use..

  • PavlinII commented  ·   ·  Flag as inappropriate

    You did not understand that this proposal extends current state and does not remove anything.

    Current longer syntax have to be preserved of course.

  • PavlinII commented  ·   ·  Flag as inappropriate

    Nick Roberts:
    DoSomething with x, y, w, h is just an example to illustrate the issue. You can always refactor many arguments into DoSomething(Args As DoSomethingArumentsWrapper) of course.

    But refactoring adds even more code and forces consumer of function to wrap arguments - add unnecessary wrapper creating code when more useful overload member is available.

    Check Rectangle class constructor. location+size constructor is available. And x+y+width+height is available as well. Selection depends on specified scenario.

    My original suggestion would save some code in scenarios when:
    - you just have more arguments of same type
    - you want to provide suitable overloasd (location+size and x+y+w+h)
    - you have more arguments of same type that can't be grouped into meaningfull wrapper (SHA as you mentioned or: From, To, CC, BCC, ReplyTo, Subject, Body etc.)
    - you do not want to write argument wrapper for small private helper functions
    OR
    - when you're writing that wrapper and you want it to have useful constructor ;)

    Inside that wrapper would be for example (prefixes ommited):
    Private x, y, w, h, Value As Integer
    And would just copy paste this into constructor parameters. Now, you have to copy it and add 4x As Integer clause.

    Even Point and Size2D constructors could use suggested feature.

    I think it might be very useful.

← Previous 1

Feedback and Knowledge Base