Wish "Default Parameter Value" of a SUB

AnandGupta

Expert
Licensed User
Longtime User
I was going though C# course and found "Default Parameter Value"

B4X:
static void MyMethod(string country = "Norway") 
{
  Console.WriteLine(country);
}

static void Main(string[] args)
{
  MyMethod("Sweden");
  MyMethod("India");
  MyMethod();
  MyMethod("USA");
}

// Sweden
// India
// Norway
// USA

I know we have made wishes from very early version of B4A (year 2016 maybe), but again I see the benefit of it, when we have big project.
We already have GetDefault() method for class, so maybe we can have the reverse "default parameter value" in the Sub.
 

emexes

Expert
Licensed User
In the meantime I've been doing workarounds like:

One-time-only Sub for shared use by Subs that have parameter defaults:
'returns array of defaults-filled-in parameters that is at least as long as the array of default values
Sub FillInDefaultParameters(ParGot() As Object, ParDefault() As Object) As Object()

    Dim NumGot As Int = ParGot.Length
    Dim NumDefault As Int = ParDefault.Length
   
    If NumGot > NumDefault Then
        Dim NumComplete As Int = NumGot
    Else
        Dim NumComplete As Int = NumDefault
    End If
   
    Dim ParComplete(NumComplete) As Object

    For I = 0 To NumComplete - 1
        Dim TempPar As Object = Null
        If I < NumGot Then
            TempPar = ParGot(I)   
        End If
        If TempPar = Null Then
            If I < NumDefault Then
                TempPar = ParDefault(I)
            End If
        End If
        ParComplete(I) = TempPar
    Next

    Return ParComplete

End Sub

Example Sub with def... uh, what it says:
Sub ExampleSubWithDefaultParameters(Par() As Object) As String
   
    Dim RealPar() As Object = FillInDefaultParameters(Par, Array As Object( _
        "25th", _
        "December", _
        2022, _
        "The Best Christmas Ever!" _
    ))
   
    Return RealPar(0) & " of " & RealPar(1) & " " & RealPar(2) & " = " & RealPar(3)
   
End Sub

Example calls:
'defaults are:                                      "25th"   "December"   2022   "The Best Christmas Ever!" 
'                                                   ======   ==========   ====   ================================
Log(ExampleSubWithDefaultParameters(Array As Object(Null   , Null       , Null , Null                             )))
Log(ExampleSubWithDefaultParameters(Array As Object(Null   , Null       , 2023 , Null                             )))
Log(ExampleSubWithDefaultParameters(Array As Object(Null   , Null       , 2020 , "the worst xmas I've ever seen?" )))
Log(ExampleSubWithDefaultParameters(Array As Object("31st" , Null       , Null , "the last day of this year."     )))
Log(ExampleSubWithDefaultParameters(Array As Object("1st"  , "January"  , 2023 , "the first day of next year."    )))
Log(ExampleSubWithDefaultParameters(Array As Object("1st"  , "August"   , Null , "Swiss National Day this year."  )))

Log output:
Waiting for debugger to connect...
Program started.
25th of December 2022 = The Best Christmas Ever!
25th of December 2023 = The Best Christmas Ever!
25th of December 2020 = the worst xmas I've ever seen?
31st of December 2022 = the last day of this year.
1st of January 2023 = the first day of next year.
1st of August 2022 = Swiss National Day this year.
 

emexes

Expert
Licensed User
In the meantime I've been doing workarounds like:

Bonus dynamic default parameters (although tbh I've never used them) (yet 🤫 ) :

B4X:
Sub ExampleSubWithDefaultParameters(Par() As Object) As String
    
    Dim RealPar() As Object = FillInDefaultParameters(Par, Array As Object( _
        "25th", _
        "December", _
        DateTime.GetYear(DateTime.Now), _
        "The Best Christmas Ever!" _
    ))
    
    Return RealPar(0) & " of " & RealPar(1) & " " & RealPar(2) & " = " & RealPar(3)
    
End Sub
 

emexes

Expert
Licensed User
Bonus dynamic default parameters (although tbh I've never used them) (yet 🤫 ) :

Just realised you can use it to "specify" the Sub's functionality according to the number and/or type of parameters... there's a word for that, but I can't think what it is.

Anyway eg:

B4X:
Sub MonthToMonthNumber(Month As Object) As Int
   
    Dim AllMonths() As String = Array As String( _
        "january", "february", "march", _
        "april", "may", "june", _
        "july", "august", "september", _
        "october", "november", "december" _
    )
   
    Dim MonthNumber As Int = 0    'pessimists of the world, unite!
   
    If Month Is Int Then    'if parameter is a number then...
        If Month >= 1 And Month <= 12 Then
            MonthNumber = Month
        End If
    else if Month Is String Then    'if parameter is a string then...
        Dim TempMonth As String = Month
        TempMonth = TempMonth.Trim.ToLowercase    'clean up to match AllMonths()

        If TempMonth.Length <> 0 Then
            Dim NumMatches As Int = 0
            For I = 0 To AllMonths.Length - 1
                If AllMonths(I).StartsWith(TempMonth) Then
                    NumMatches = NumMatches + 1
                    MonthNumber = I + 1    'reset to 0 if not exactly one match      
                End If
            Next
            If NumMatches <> 1 Then
                MonthNumber = 0
            End If
        End If
    End If
   
    Return MonthNumber    '0 = month not 100% certain (or could return Null to flag same)
   
End Sub

B4X:
Dim TestMonths() As Object = Array As Object( _
    5, 11, 15, 21, _
    4.9, 5.0, 5.1, 5.2, _
    "J", "Ja", "Jan", "Janu", _
    "Ju", "Jun", "Jul", _
    "O", "OC", "OCT", "OCTO", "OCTOP", "OCTOPUSSY", _
    "M", "Mo", "Mon", "S", "Sa", "Sat", "Wed" _
)

For Each O As Object In TestMonths
    Log(                                     _
        (O Is Int)                   & TAB & _
        (o Is String)                & TAB & _
        (O Is Float Or O Is Double)  & TAB & _
        O                            & TAB & _
        MonthToMonthNumber(O)                _
    )
Next

Log output:
Waiting for debugger to connect...
Program started.
true    false    false    5    5
true    false    false    11    11
true    false    false    15    0
true    false    false    21    0
false    false    true    4.9    0
false    false    true    5.0    0
false    false    true    5.1    0
false    false    true    5.2    0
false    true    false    J    0
false    true    false    Ja    1
false    true    false    Jan    1
false    true    false    Janu    1
false    true    false    Ju    0
false    true    false    Jun    6
false    true    false    Jul    7
false    true    false    O    10
false    true    false    OC    10
false    true    false    OCT    10
false    true    false    OCTO    10
false    true    false    OCTOP    0
false    true    false    OCTOPUSSY    0
false    true    false    M    0
false    true    false    Mo    0
false    true    false    Mon    0
false    true    false    S    9
false    true    false    Sa    0
false    true    false    Sat    0
false    true    false    Wed    0
 

AnandGupta

Expert
Licensed User
Longtime User
We are missing the point here.

Example:
First I made SUB PopUp(nWidth, nHeight) which show at center of screen and used it every projects, big or small.
Next I needed to show it at bottom right, so PopUp(nWidth, nHeight, nLeft, nRight), but all the uses code of the PopUp() in all projects, gives error in IDE.

Making every SUB as PopUp(cObject) or PopUp(Array) is not the same. We can not see the parameter requirement here from the syntax of PopUp.
Please note B4X has 3 CallSubDelay for new parameters, and never use Object or Array as parameters for all future versions.

The default value of a SUB does not come when we first make a new SUB. It is done on the project requirement. Later when a different project requires extra parameter for same SUB, we need to the default value, so that all old codes do not generate error.

I have been using this feature in all programming languages I use. It will only benefit the developer if B4X has this feature too.
 

emexes

Expert
Licensed User
We can not see the parameter requirement here from the syntax of PopUp.

I'd have to say that the IDE makes a sterling effort, way above its paygrade, if you give it a little help:

1665838937832.png
 

AnandGupta

Expert
Licensed User
Longtime User
I'd have to say that the IDE makes a sterling effort, way above its paygrade, if you give it a little help:

View attachment 134843
Still not the same as adding 'help text' makes IDE not to throw the error.
We still have to make changes in all codes manually.

Default parameter stops the IDE from throwing error.
 

William Lancee

Well-Known Member
Licensed User
Longtime User
I am not a full-time developer, but I can appreciate wanting to extend existing functionality of subroutines.
When I have been in situations as described in #7 (and that seems to happen daily), I need to make a sub with a different name.

Like many functions in B4X (Substring, CallSubDelayed, Initialize, etc.) I add a suffix with the number of parameters expected.
This prevents an error in existing code, and makes it clear what the intention is for the new sub which will be used in future code.

I do believe that this design choice for B4X is intentional, and not an omission.
I also have coded in other computer languages with the feature in #1, but thinking back about it, I didn't use it much (or ever).
I am not sure why not, but maybe it has to do with the fact that defaults can cause hard-to-find bugs.
There are no errors, but the program doesn't work the way you expect.

In any case this topic deserves further discussion. I thank @AnandGupta for bringing it up.
 

AnandGupta

Expert
Licensed User
Longtime User
I am not sure why not, but maybe it has to do with the fact that defaults can cause hard-to-find bugs.
There are no errors, but the program doesn't work the way you expect.
If you are self developer.

As a senior developer I am responsible for 15 developers under me. I develop all black boxes for them to use in many different projects as required by our company. If any black box need a new parameter, the default, saves those juniors to use their old projects as it is with the new class, when I release it.

Hope one remembers why B4X created GetDefault() method ?
When a creator of a class added new property in new version and the user uses it in old project where the property was not there, it gave error.
The GetDefault() stops the error.
 

Sandman

Expert
Licensed User
Longtime User
It might also be good to point out it isn't some weird and obscure feature being requested. This is a standard feature in many languages, for instance python and php. (Python also uses named parameters, which this thread and wish doesn't cover.)

It's also an awesome way to not have to use the pattern of MyFunction, MyFunction2 and MyFunction3. That has always felt a bit like a clutch to me.
 

emexes

Expert
Licensed User
Still not the same as adding 'help text' makes IDE not to throw the error.
We still have to make changes in all codes manually.
Default parameter stops the IDE from throwing error.

Hey I'm just doing this for fun, and I agree that there are syntactic niceties that would make B4X nicer to use. ☮️🍻🙃

Doing roll-your-own variable parameters etc is a bit verbose, I grant you, but like all Subs it's write-once, use-many.

Plus you can do precisely what you need done, unconstrained by the language designer's field of view (although presumably you'd still be able to do this anyway, ie adding polymorphism etc to B4X is unlikely to rule out still using these Array As Object techniques when they are useful).

Sub with variable number of parameters plus parameter defaults plus parameter type checking:
'Parameters are: Array As Object(
'    nWidth As Int  (default = 100)
'    nHeight As Int  (default = 50)
'    nLeft As Int  (default = 325)
'    nRight As Int  (default = 475)
'    Title As String  (default = "B4X FTW!")
')
Sub AnandVarPar(Par() As Object) As String

    If Par.Length < 2 Then "".SubString(1)
    If Par.Length > 5 Then "".SubString(1)
  
    Dim UsePar() As Object = Array As Object(100, 50, 325, 475, "B4X FTW!")
  
    For I = 0 To Par.Length - 1
        If Par(I) <> Null Then
            UsePar(I) = Par(I)
        End If
    Next
  
    If Not(UsePar(0) Is Int)    Then "".SubString(1)
    If Not(UsePar(1) Is Int)    Then "".SubString(1)
    If Not(UsePar(2) Is Int)    Then "".SubString(1)
    If Not(UsePar(3) Is Int)    Then "".SubString(1)
    If Not(UsePar(4) Is String) Then "".SubString(1)

    Dim nWidth  As Int    = UsePar(0)
    Dim nHeight As Int    = UsePar(1)
    Dim nLeft   As Int    = UsePar(2)
    Dim nRight  As Int    = UsePar(3)
    Dim Title   As String = UsePar(4)
  
    Log("Parameters are " & nWidth & ", " & nHeight & ", " & nLeft & ", " & nRight & ", """ & Title & """")
  
End Sub

Test of above:
Sub TrySubTipsInHere
  
    AnandVarPar(Array As Object(123, 456))
    AnandVarPar(Array As Object(123, 456, 78))
    AnandVarPar(Array As Object(123, 456, 78, 90))
    AnandVarPar(Array As Object(123, 456, 78, 90, "Anand Was Here"))
    AnandVarPar(Array As Object(Null, Null, 12, 34, Null))
  
    'and for one show only...
    AnandVarPar(Array As Object(123, 456, "78", "90"))
  
End Sub

Log output:
Waiting for debugger to connect...
Program started.
Parameters are 123, 456, 325, 475, "B4X FTW!"
Parameters are 123, 456, 78, 475, "B4X FTW!"
Parameters are 123, 456, 78, 90, "B4X FTW!"
Parameters are 123, 456, 78, 90, "Anand Was Here"
Parameters are 100, 50, 12, 34, "B4X FTW!"
Error occurred on line: 40 (B4XMainPage)
 
Last edited:

AnandGupta

Expert
Licensed User
Longtime User
Hey I'm just doing this for fun,
This summarize the message.

And for serious development environment with teams, default does helps when you have many running and maintained paid projects across the spectrum.
 

emexes

Expert
Licensed User
Like many functions in B4X (Substring, CallSubDelayed, Initialize, etc.) I add a suffix with the number of parameters expected.
That's not a bad a pretty good idea. If not for the first implementation, at least for the subsequent changes.

As I understand it, the first implementation might look like:
B4X:
Sub PopUp(nWidth As Int, nHeight As Width)
    'do stuff
End Sub

and then the new improved implementation like:
B4X:
Sub PopUp4(nWidth As Int, nHeight As Width, nLeft As Int, nRight As Int)
    'do stuff
End Sub

'support code that uses previous version
Sub PopUp(nWidth As Int, nHeight As Width)
    PopUp4(nWidth, nHeight, DefaultnLeft, DefaultnRight)
End Sub

Lol that just gave me flashbacks to replacing Microsoft ISAM with Btrieve, and writing a whole lot of ISAM-lookalike functions that called their Btrieve equivalents, so that the rest of the program mostly compiled and ran just like it used to.
 

William Lancee

Well-Known Member
Licensed User
Longtime User
The 2 in Substring2, CallSubDelayed2, Initialize2 refers to the version#. But for Substring that coincides with the # of parameters.
In CallSubDelayed2, the number of parameters is 3. In Initialize2 the # of parameters could be anything.

For me it is just a mnemonic device for new versions of Subs. I am not suggesting it would work for others.

@emexes I too have bad memories of wrapping the new with the old, or old with the new, or laborious global search and replace.

@AnandGupta as soon as one works with a group of people, a whole other set of considerations come into play, I get that.
Your wish come true would be very useful.
 
Last edited:

AnandGupta

Expert
Licensed User
Longtime User
but how easy is to add it... now... only Erel knows that :)
Agree here and have hope as he has shown extreme intelligence many times in making features for B4X.

+may be an option like this will create compatibility errors...
No compatibility error, as the default value is used when not passed.
We are passing all required values to Sub till now.
 

Sandman

Expert
Licensed User
Longtime User
Considering the talent Erel has demonstrated by creating B4X I cannot for the life of me think that this would pose a large challenge for him.

Instead I think it will mostly come down to whether it fits his vision for B4X, and as far as I am able to reverse engineer his vision based on previous discussions, the answer will be no. It adds something extra that can be complicated to understand, and that doesn't fit his vision to make the language as accessible and low-barrier as possible for newcomers. (Granted, that's my interpretation of his vision, which might be severly faulty and overly simple. I'm not aware of him actually describing it somewhere. Apologies all around if I'm way off base.)

No compatibility error, as the default value is used when not passed.
We are passing all required values to Sub till now.
💯
 

agraham

Expert
Licensed User
Longtime User
I wrote in C# for years and in that time successive version grew things like this that in my opinion contribute nothing and obfuscate understanding. Having worked with Erel from the early days I'm pretty sure Sandman is correct and Erel would see it as an unnecessary complication to what is intended to be a straightforward language.
 
Top