Theory
The same 3 lines, 14 times
ShopKeeper computes a line total (price times quantity, minus any discount) in 14 different places: at the till, in the day report, in the return screen...
You already know this smell from BCA403 and BCA104: repeated logic belongs in ONE named place, called wherever needed.
VB.NET splits that idea into 2 kinds of procedure, and the split is graded: a Sub DOES something; a Function ANSWERS something. Choosing wrongly is lost marks and awkward code.
Theory
Module, Sub, Function
A Module is a container whose procedures are shared: callable without creating any object (Java's static, wearing VB clothes). Console programs start at Sub Main inside one.
Sub PrintBill(...) performs an action; it returns nothing. Ends with End Sub.
Function LineTotal(...) As Double computes and returns a value: the return type follows As, the answer leaves via Return. Ends with End Function.
Rule of thumb: if the caller needs a value back, it is a Function; if the caller needs an effect, a Sub.
Practical
Billing helpers, all 4 features at once
Module Billing
' Optional parameter: default used when caller omits it
Function LineTotal(ByVal price As Double, ByVal qty As Integer,
Optional ByVal discount As Double = 0) As Double
Return price * qty * (1 - discount)
End Function
' ParamArray: accepts ANY number of line totals
Function GrandTotal(ByVal ParamArray lines() As Double) As Double
Dim sum As Double = 0
For Each l As Double In lines
sum += l
Next
Return sum
End Function
Sub Main()
Dim t1 As Double = LineTotal(40, 3) ' 120 (no discount)
Dim t2 As Double = LineTotal(100, 2, 0.1) ' 180 (10% off)
MsgBox("Bill: " & GrandTotal(t1, t2)) ' Bill: 300
End Sub
End Module
Theory
ByVal and ByRef: copy or the thing itself
Every parameter travels one of 2 ways:
- ByVal (the default): the procedure receives a copy; whatever it does, the caller's variable is untouched
- ByRef: the procedure receives the caller's variable itself; assignments inside CHANGE it outside
Sub ApplyFestivalDiscount(ByRef price As Double)
price = price * 0.9
End Sub
After ApplyFestivalDiscount(rate), the caller's rate has genuinely shrunk. The same body with ByVal would discount the copy and change nothing.
Quiz
Sub Cut(ByVal p As Double) : p = p - 10 : End Sub. Caller: Dim price As Double = 50 : Cut(price) : MsgBox(price). What shows?
- 40: the Sub subtracted 10 from price
- 50: Cut changed only its own copy; ByVal protects the caller's variable
- Compile error: a Sub cannot modify its parameters
- 0: price is reset when the Sub ends
Show the answer
50: Cut changed only its own copy; ByVal protects the caller's variable
ByVal hands Cut a copy named p; the subtraction happens to the copy, which evaporates when the Sub ends, so the caller still sees 50. Option A describes what ByRef would do, and the one-word difference in the signature is the entire question. Option C is false: modifying a parameter is legal, just locally scoped under ByVal. Since ByVal is VB.NET's DEFAULT, the takeaway is comforting: procedures cannot damage your variables unless you explicitly hand them over with ByRef.
Think first
Trace the bill
Using the listing: LineTotal(40, 3), then LineTotal(100, 2, 0.1), then GrandTotal of both. Compute all 3 numbers before tapping.
Show the answer
LineTotal(40, 3): discount omitted, so the Optional default 0 applies: 40 × 3 × 1 = 120. LineTotal(100, 2, 0.1): 100 × 2 × 0.9 = 180. GrandTotal(120, 180): ParamArray receives the 2 values as an array and the loop sums them: 300. Notice each feature earning its keep: the default spared the common case, ParamArray took exactly as many lines as the bill happened to have: 2 today, 9 tomorrow, same call.
Watch out
The placement rules examiners test
Optional parameters must declare a default (Optional ByVal d As Double = 0) and must come after all required parameters: Optional-then-required does not compile.
ParamArray must be the last parameter, and there can be only one.
Function without Return: a path that never returns hands back the type's default (0 for numbers) and usually a wrong bill: make every path Return explicitly.
Theory
Translating from Java
Map it once: Module procedures are Java's static methods; Sub is void; Function is a typed method. Java had no ByRef (object references passed by value came close but not equal), no Optional defaults (you overloaded instead) and varargs (String...) as its ParamArray. So VB.NET is here mostly MORE convenient. These helpers become button-click code in Unit 3: the till's Total button will call LineTotal exactly as Main does today.
Summary
Key takeaways
- Module = container of shared procedures; Sub Main is the console entry point.
- Sub performs an action (no return value); Function ... As Type returns one via Return.
- ByVal (default) passes a copy: the caller's variable is safe; ByRef passes the variable itself: changes stick.
- Optional parameters need a default value and sit after required ones.
- ParamArray gathers any number of arguments into an array; last parameter only.
- Worked bill: 40×3 = 120, 100×2×0.9 = 180, grand total 300.
- Memory hook: Sub does, Function answers, ByRef hands over the original.