sciBASIC/docs
xieguigang cab444e0aa update source file banners 2022-03-15 21:49:30 +08:00
..
guides update source file banners 2022-03-15 21:49:30 +08:00
images rollback repostiroy 2018-09-08 00:27:24 +08:00
CNAME rollback repostiroy 2018-09-08 00:27:24 +08:00
README.md rollback repostiroy 2018-09-08 00:27:24 +08:00
_config.yml rollback repostiroy 2018-09-08 00:27:24 +08:00

README.md

Code style guidelines for Microsoft VisualBasic

----======= TOC =======----

1. Architecture of VisualBasic CLI program

There is a VisualBasic application helper module that define in the namespace: Microsoft.VisualBasic.App

A special function named main is the starting point of execution for all VisualBasic programs. A VisualBasic CLI application should define the Main entry point in a Module which is named Program and running from a Integer state code returns Function Main. By using the name of Program for the entry point module, this will makes more easily recognize of your program's entry point.

Module Program

    ''' <summary>
    ''' This is the main entry point of your VisualBasic application.
    ''' </summary>
    ''' <returns></returns>
    Public Function Main() As Integer
        Return GetType(CLI).RunCLI(App.CommandLine)
    End Function
End Module

By using a Integer Function instead of Sub in VisualBasic, this makes your code style is more standard compare with the main function from C++.

int main(int argc, char *argv[]) {
	// blablabla...
}

In the above example, Where, the type CLI is the CLI interface which it is a module that contains all of the CLI command of your application. And the extension function RunCLI is a CLI extension method from the VisualBasic App helper: Microsoft.VisualBasic.App. The property value of App.CommandLine is the commandline argument of current application that user used for start this application and calling for some CLI command which is exposed in your application's CLI module.

1.1. How to define the CLI module?

A Module is a static Class type in the VisualBasic, and it usually used for the API exportation and common method definition for a set of similarity or functional correlated utility functions.

And then so that the CLI module in the VisualBasic can be explained as: A module for exposed the CLI interface API to your user.

Here is an example:

Partial Module CLI

    <ExportAPI("/Print")>
    <Usage("/Print /in <inDIR> [/ext <ext> /out <out.Csv>]")>
    <Description("Help info")>
    Public Function Print(args As CommandLine.CommandLine) As Integer
        Dim ext$ = (args <= "/ext") Or "*.*".AsDefault
        Dim inDIR As String = args <= "/in"
        Dim out As String = args.GetValue("/out", inDIR.TrimDIR & ".contents.Csv")
        Dim files As IEnumerable(Of String) = ls - l - r - ext <= inDIR
        Dim content = LinqAPI.Exec(Of NamedValue(Of String)) _
_
            () <= From file As String
                  In files
                  Let name As String = file.BaseName
                  Let genome As String = file.ParentDirName
                  Select New NamedValue(Of String) With {
                      .Name = name,
                      .Value = genome
                  }

        Return content _
            .SaveTo(out) _
            .CLICode
    End Function
End Module

This example code can be found at: github

1.2. How to expose the CLI API in your application?

A wrapper for parsing the commandline from your user is already been defined in namespace: Microsoft.VisualBasic.CommandLine

And the CLI interface should define as in the format of this example:

Imports Microsoft.VisualBasic.CommandLine
Imports Microsoft.VisualBasic.CommandLine.Reflection

<ExportAPI("/Print")>
<Usage("/Print /in <inDIR> [/ext <ext> /out <out.Csv>]")>
<Group("Function Group Name")>
<Argument("/in", AcceptTypes:={GetType(String)}, Description:="The input directory path.")>
<Argument("/out", True, AcceptTypes:={GetType(NamedValue(Of String))}, Description:="The output csv data.")>
Public Function CLI_API(args As CommandLine) As Integer
  • ExportAPI attribute that flag this function will be exposed to your user as a CLI command.
  • Group attribute that can grouping this API into a function group
  • Argument attribute that records the help information of the parameter in the CLI.
  • Usage attribute tells your user how to using your CLI API
  • Description attribute give the brief function description about this CLI command.

1.2.1. Auto document feature from VisualBasic CLI framework

Once you have defined these five attribute for your CLI API, then you can using the App ? command command for get the API summary from the auto document feature, example as:

Can generates such well formatted auto document:

1.3. Using the VisualBasic CommandLine Parser

For learn how to using the CommandLine Parser, we first lean the syntax of the VisualBasic commandline arguments. A typical commandline arguments in VisualBasic is consist of two parts:

  1. Command Name
  2. Arguments

Here is a simple example:

App.exe /API1 /test /msg "Hello World!!!" /test2-enable /test3-enable

Where in this CLI, token App.exe is the executable file name of your application; And /API1 token, is the Command Name; And then the last tokens are the parameter arguments, using the commandline in VisualBasic just like function programming in VisualBasic:

Module App
    Public Function API1(test As Boolean, 
                         msg As String, 
    			 test2Enable As Boolean, 
    			 test3Enable As Boolean) As Integer
End Module

You call your CLI command in the console terminal is just like call a function in the VisualBasic Code:

Dim code As Integer = App.API1(True, "Hello World!!!", True, True)

NOTE: There is no order of the VisualBasic CLI arguments, so that all of these CLI examples are equals to each other:

#!/bin/bash

App.exe /API1 /msg "Hello World!!!" /test2-enable /test3-enable /test
App.exe /API1 /msg "Hello World!!!" /test /test2-enable /test3-enable
App.exe /API1 /test /test2-enable /test3-enable /msg "Hello World!!!"
App.exe /API1 /test2-enable /test /test3-enable /msg "Hello World!!!"

Simple Example of VisualBasic CLI application(Example source code at here):

Imports Microsoft.VisualBasic.CommandLine
Imports Microsoft.VisualBasic.CommandLine.Reflection

Module Program

    Public Function Main() As Integer
        Return GetType(CLI).RunCLI(App.CommandLine)
    End Function
End Module

Module CLI

    <ExportAPI("/API1",
         Info:="Puts the brief description of this API command at here.",
         Usage:="/API1 /msg ""Puts the CLI usage syntax at here""",
         Example:="/API1 /msg ""Hello world!!!""")>
    Public Function API1(args As CommandLine) As Integer
        Call Console.WriteLine(args("/msg"))
        Return 0
    End Function
End Module

Here are some mostly used function in VisualBasic CLI parser Example CLI is:

App.exe /Test-Example /b /n 52 /xml "~/test.Xml" /num_threads 96 /path "~/tmp/test.log"
Function Usage Example
GetBoolean(String) As Boolean Get a boolean flag argument from the CLI Dim b As Boolean = args.GetBoolean("/b")
GetInt32(String) As Integer Get a parameter value as Integer Dim n As Integer = args.GetInt32("/n")
GetObject(Of T)(String, System.Func(Of String, T)) As T Get a parameter string value and then apply a string parser on it for load an .NET object Dim x As T = args.GetObject(of T)("/xml", AddressOf LoadXml)
GetValue(Of T)(String, T, System.Func(Of String, T)) As T Get a parameter value, if the parameter is not exist, then default value will be returns, this method is usually used on optional value Dim n As Long = args.GetValue("/num_threads", 100L)
Item(String) As String Default readonly property for read string value of a specific parameter Dim path As String = args("/file")

2. List(Of T) operation in VisualBasic

For enable this language syntax feature and using the list feature in this section, you should imports the namespace Microsoft.VisualBasic.Language at first

Dim source As IEnumerable(Of <Type>)
Dim list As New List(of <Type>)(source)

For Add a new instance

list += New <Type> With {
    .Property1 = value1,
    .Property2 = value2
}

For Add a sequence of new elements

list += From x As T
    	In source
    	Where True = <test>
        Select New <Type> With {
            .Property1 = <expression>,
            .Property2 = <expression>
        }

if want to removes a specific element in the list

list -= x

Or batch removes elements:

list -= From x As T
    	In source
        Where True = <test>
        Select x

Here is some example of the list + operator

' This add operation makes the code more easily to read and understand:
' This function returns a list of RfamHit element and it also merge a
' list of uncertainly elements into the result list at the same time
Public Function GetDataFrame() As RfamHit() Implements IRfamHits.GetDataFrame
    Return hits.ToList(Function(x) New RfamHit(x, Me)) + From x As Hit
                                                         In Uncertain
                                                         Select New RfamHit(x, Me)
End Function

And using the + operator for add a new object into the list, this syntax can makes the code more readable instead of the poorly readable code from by using method List(of T).Add:

genomes += New GenomeBrief With {
    .Name = title,
    .Size = last.Size,
    .Y = h1
}

' Using the + operator to instead of this poorly readable function code
genomes.Add(New GenomeBrief With {
    .Name = title,
    .Size = last.Size,
    .Y = h1
})

3. The VisualBasic inline assign syntax

Like other C family language, VB is also have the inline assign operation syntax, here is how to enable this language syntax in VB:

Imports Microsoft.VisualBasic.Language

Dim line As New Value(Of String)

Do While Not (line = reader.ReadLine) Is Nothing
    ' blablabla
Loop

Enable this language syntax just very easy, wrapping your variable object type with Value(Of T) in VB language.

4. Default Value in VisualBasic

' using default value is more elegant than using If expression
' and much more natural english language way: 
Public Sub Print(Optional device As TextWriter = Nothing)

    ' using device object or console output as default if device is nothing
    With device Or Console.Out.AsDefault
    
        ' blablabla
    End With
End Sub

Public Sub Print(Optional device As TextWriter = Nothing)
    With If(device Is Nothing, Console.Out, device)
    
        ' blablabla
    End With
End Sub

5. The Unix bash syntax for listing files

Here is how to using this bash syntax that you can used for listing files/folders in VisualBasic language:

Imports Microsoft.VisualBasic.Language.UnixBash

Return (ls - l - r - wildcards("*.csv") <= DIR) _
      .Select(AddressOf ODEsOut.LoadFromDataFrame) _
      .Sampling(eigenvector, partN)

' Or used in For Loop
For Each file As String In ls - l - r - wildcards("*.csv") <= DIR
    ' blablabla
Next

In the newer version of this VB runtime, the wildcards can be simplify as a string or string array if you are not feeling confused with this syntax example:

Imports Microsoft.VisualBasic.Language.UnixBash

' A more simple version of the syntax 
Return (ls - l - r - "*.csv" <= DIR) _
      .Select(AddressOf ODEsOut.LoadFromDataFrame) _
      .Sampling(eigenvector, partN)

' Or used in For Loop
For Each file$ In ls - l - r - {"*.csv", "*.tsv"} <= DIR
    ' blablabla
Next

6. VB specific With anonymous variable

When you are dealing the variable with an array, usually you are going to do in this style:

Dim array As <Class>()

For i% = 0 To array.Length - 1
    Dim o = array(i)

    If <blablabla(o)> Is True Then
        Return i%
    End If
Next

But by using the With anonymous variable syntax, the code would be more brief and better:

Dim array As <Class>()

For i% = 0 To array.Length - 1
    With array(i)

        If <blablabla(.Property)> Is True Then
            Return i%
        End If
    End With
Next
Example
Public Function IndexOf(Id As Char) As Integer
    For i As Integer = 0 To Catalogs.Length - 1
        With Catalogs(i)
            If .SubClasses.ContainsKey(Id) Then
                Return i
            End If
        End With
    Next

    Return -1
End Function

And also you can combine With with function returns value. And so how to reference this anonymous variable, and get itself? Just using a very simple extension method ref(), which is located at namespace Microsoft.VisualBasic.Language.

With function_calls()
    ' blablabla
    Return .ref
End With

''' <summary>
''' Extension method for VisualBasic ``With`` anonymous variable syntax source reference helper
''' </summary>
''' <typeparam name="T"></typeparam>
''' <param name="x"></param>
''' <returns></returns>
<Extension> Public Function ref(Of T)(x As T) As T
    Return x
End Function

7. Type char coding style

The type char code just working on the .NET primitive type, like String, Integer, Long, Double, Char, etc. Using the type char code can makes your code more brief and readable, give your code more VisualBasic-ish.

It is recommended that using type char in the parameter declaring of a function or method, local variable in a method/function, internal module fields.

Not recommended that using type char for Class/Structure Property.

8. VisualBasic identifer names

8.1. 1. Directory type

If possible, then all of the directory path variable can be UPCASE, such as:

Dim DIR As String = "/home/xieguigang/Downloads"
Dim EXPORT As String = "/usr/lib/GCModeller/"

8.2. 2. Module variable

  • All of the module variable should in format like _lowerUpper if the variable is private
  • But if the variable is Public or Friend visible, then it should in format like UpperUpper

Here is some example:

' Private
Dim _fileName As String
Dim _inDIR As Directory

' Public
Public ReadOnly Property FileName As String
Public ReadOnly Property InDIR As Directory

8.3. 3. Local varaible and function parameter

If possible, all of the local varaible within a function or sub program and the parameters of a function, should be in format lowerUpper

8.4. 4. Function And Type name

For Public member function, the function name is recommended in formats UpperUpper, but if the function is Private, Friend, or Protected visible, then your function is recommended start with two underlines, likes __lowerUpper. The definition of the Class, Structure names is in the same rule as function name.

Here is some function name examples(Example picked from here):

' Private
Private Function __worker(Of T As I_GeneBrief)(
                        genome As IGenomicsContextProvider(Of T),
                         getTF As Func(Of Strands, T()),
                    getRelated As Func(Of T, T(), Integer, T()),
                      numTotal As Integer,
                        ranges As Integer) As Density()
' Public
Public Function DensityCis(Of T As I_GeneBrief)(
                         genome As IGenomicsContextProvider(Of T),
                             TF As IEnumerable(Of String),
                Optional ranges As Integer = 10000) As Density()

  • Interface type name should start with a upcase character I, like IEnumerable, IList, etc
  • Enum type name should end with a lower case character s, like MethodTypes, FormatStyles

8.5. Using underline in namming

When the identifier name require of the underline symbol _, then it is recommended that first word should be an all UPCASE brief code and the next word is an all lowcase word. For example,

Dim GO_term$

' this would be better and more balance than
' Dim go_term$
' or
' Dim Go_term$

At last, for improves of the code readable, try Make your identifier name short enough as possible

Code standard overview example

9. String manipulate

1. String.Format

For formatted a string output, then recommended used String.Format function or string interpolate syntax in VisualBasic language. And by using the String.Format function, then format control string is recommended puts in a constant variable instead of directly used in the format function:

Const OutMsg As String = "Hello world, {0}, Right?"
' blablabla.......
Dim msg As String = String.Format(OutMsg, name)
2. String contacts

For contacts a large amount of string tokens, the StringBuilder is recommended used for this job, not recommend directly using & operator to contacts a large string collection due to the reason of performance issue.

' Convert the input string to a byte array and compute the hash.
Dim data As Byte() = md5Hash.ComputeHash(input)

' Create a new Stringbuilder to collect the bytes
' and create a string.
Dim sBuilder As New StringBuilder()

' Loop through each byte of the hashed data
' and format each one as a hexadecimal string.
For i As Integer = 0 To data.Length - 1
	sBuilder.Append(data(i).ToString("x2"))
Next i

Return sBuilder.ToString() ' Return the hexadecimal string.

If you just want to contact the string, then a shared method String.Join is recommended used. If the string tokens will be join by a specific delimiter, then using String.Join instead of StringBuilder.Append

Dim tokens As String()
Dim sb As New StringBuilder

For Each s As String In tokens
	Call sb.Append(s & " ")
Next
Call sb.Remove(sb.Length -1)

Or just use String.Join, this method is more clean and readable than StringBuilder.Append:

Dim tokens As String()
Dim out As String = String.Join(" ", tokens)
3. String interpolate

The string interpolate syntax in VisualBasic language is recommended used for build SQL statement and CLI arguments as this syntax is very easily for understand and code readable:

Dim SQL As String = $"SELECT * FROM table WHERE id='{id}' AND ppi>{ppi}"
Dim CLI As String = $"/start /port {port} /home {PathMapper.UserHOME}"

So, using this syntax feature makes your code very easy for reading and understand the code meaning, right?

9.1. Linq Expression

All of the Linq Expression is recommended execute using LinqAPI if the output type of the expression is a known type:

9.2. Instantiation

For define a new object, a short format is recommended:

Dim x As New <Type>

If the type you want to create object instance can be initialize from its property, then the With keyword is recommended to used:

Dim MyvaCog As MyvaCOG() = LinqAPI.Exec(Of MyvaCOG) <= 
_
	From gene As GeneDumpInfo
        In GenomeBrief
        Select New MyvaCOG With {
            .COG = gene.COG,
            .QueryName = gene.LocusID,
            .QueryLength = gene.Length
        }

9.3. Extension Method And Linq

With the extension method, then you can implementes a Fully Object-Oriented coding style, as you can add extend any method or function onto any type of object.

For example:

''' <summary>
''' Make directory
''' </summary>
''' <param name="DIR"></param>
<Extension> Public Sub MkDIR(DIR As String)
    Call FileIO.FileSystem.CreateDirectory(DIR)
End Sub

This string object extension method will makes the string working as a directory object:

Call "D:\MyData\".MkDIR

If another Linq expression is internal inner your Linq expression, then these two staggered linq expression will messing up your coding style, and then using the Linq extension instead of the Linq expression for your internal linq expression that would be good.

Example:


Try avoid the style like (Linq Expression).Method, you should folding the extension to the next line, and this would be more clear for the reading.

Call (From x In data Select x.Properties.Length Distinct) _
    .ToArray _
    .GetJson _
    .__DEBUG_ECHO
Javascript like style

The Javascript like coding style is recommended combined with the extension method style. If the extension calling is very long, then folding in the javascript style that would be great. For example:

This is the bad style:

For Each line$ In lines

    Yield New WordTokens With {
        .name = line.Trim(" "c, ASCII.TAB),
        .tokens = line.Trim.StripSymbol.Split.Distinct.Where(Function(s) Not String.IsNullOrEmpty(s.Trim(ASCII.TAB))).ToArray
    }
Next

This is great style:

For Each line$ In lines

    Yield New WordTokens With {
        .name = line.Trim(" "c, ASCII.TAB),
        .tokens = line.Trim _
            .StripSymbol _
            .Split _
            .Distinct _
            .Where(Function(s) Not String.IsNullOrEmpty(s.Trim(ASCII.TAB))) _
            .ToArray
    }
Next

Another great style example:

Dim exp As Expression = expression _
    .Split(__dels) _
    .Select(Function(s) s.Trim(" "c, ASCII.TAB)) _
    .Where(Function(s) Not String.IsNullOrEmpty(s)) _
    .JoinBy(" AND ") _
    .Build()

Return Function(text) If(exp.Match(text), 1.0R, 0R)

10. Appendix

Here are tables of names that i used in my programming, and continues updated....

1.Some common used name for common types
System.TypeRecommend NameExample
System.Text.StringBuilder sb
Dim sb As New StringBuilder
System.String s, str, name, sId, id, x
Dim s As String
Dim str As String
Dim name As String
Dim sId As String
Dim id As String
Dim x As String
System.Integer, System.Long i, j, n, x
Dim i As Integer
Dim j As Integer
Dim n As Integer
Dim x As Integer
System.Object x, o, obj, value
Dim x As Object
Dim o As Object
Dim obj As Object
Dim value As Object
2.Name for some meaning
MeaningRecommend NameExample
Commandline arguments args, CLI
Dim args As CommandLine
Dim CLI As String
Dim args As String()
SQL query SQL, sql, query
Dim SQL As String = "SELECT * FROM table LIMIT 1;"
Iterator i, j, k, l
For i As Integer = 0 to [stop]
    For j As Integer = i to [stop]
        For k As Integer = j to [stop]
        Next
    Next
Next

Dim l As Integer = 100

Do while l = 100 ' blablabla... Loop

Linq query expressionLQuery
Dim LQuery = From path As String
             In ls -l -r -wildcards("*.Xml") <= DIR
             Where InStr(path.BaseName, "xcb") = 1
             Select path.LoadXml(Of KEGG.DBGET.Module)
Query Result/Function Returnsresult, rtvl
Dim result As [Module]() = LinqAPI.Exec(Of [Module]) <= 
_
    From path As String
    In ls -l -r -wildcards("*.Xml") <= DIR
    Where InStr(path.BaseName, "xcb") = 1
    Select path.LoadXml(Of KEGG.DBGET.Module)

Return result

DirectoryDIR, out, inDIR
Dim files As IEnumerable(Of String) = 
    ls -l -r -wildcards("*.Xml") <= DIR
jsonjson, JSON
Dim JSON As String = (ls -l -r -"*.json" <= DIR).GetJson
data framedf, ds, data
Dim df As DataFrame = DataFrame.CreateObject(path)
Network objectsnet, network, node, nodes, edge, edges
Dim net As Network = Network.Load(DIR)

net += New Node With { .Identifier = "Linq" } net += New Edge With { .FromNode = "Linq", .ToNode = "SQL" } Return net >> Open("./test.net/")

A line of text in a text file line
Dim line$ = path.ReadFirstLine
Lambda expression parameter
  • For generic object, using name:
    x, o;
  • For numeric object, using name:
    x, y, z, a, b, c, n, i;
  • For string and char, using name:
    s, c;
  • For System.Type, using name:
    t
  • Dim result = array.Select(Function(x) x.Name)
    Dim value = array _
        .Select(Function(x) x.value) _
        .Select(Function(t) t.FullName) _
        .JoinBy("+")