I have several functions that all take the same 4 arguments. How do I clean this up in EK9?
← Classes and OOP · Ref: Q1064
Extract a record. Group the repeated parameters into a record type and pass that instead.
BEFORE (repeated arguments):
calculateTotal() as pure -> price as Float quantity as Integer discount as Float taxRate as Float <- rtn as Float: ...
formatInvoice() as pure -> price as Float quantity as Integer discount as Float taxRate as Float <- rtn as String: ...
isValidOrder() as pure -> price as Float quantity as Integer discount as Float taxRate as Float <- rtn as Boolean: ...
AFTER (record parameter):
defines record OrderLine price as Float: 0.0 quantity as Integer: 0 discount as Float: 0.0 taxRate as Float: 0.0 default operator
calculateTotal() as pure -> order as OrderLine <- rtn as Float: ...
formatInvoice() as pure -> order as OrderLine <- rtn as String: ...
Benefits:
- One place to add a new field (not 4 function signatures)
- Record fields are public so functions access them directly
- Records get default operators (==, $, #?, etc.) for free
- The record is a reusable type across your module
See Q97 for record basics. See Q1060 for record fields being public. See Q116 for default operator.
Example
#!ek9 defines module qa.classesandoop.extractrecord defines record OrderLine price as Float: 0.0 quantity as Integer: 0 discount as Float: 0.0 taxRate as Float: 0.0 OrderLine() -> price as Float quantity as Integer discount as Float taxRate as Float this.price :=: price this.quantity :=: quantity this.discount :=: discount this.taxRate :=: taxRate default operator defines function calculateTotal() as pure -> order as OrderLine <- rtn as Float? subtotal <- order.price * order.quantity discounted <- subtotal - (subtotal * order.discount) rtn: discounted + (discounted * order.taxRate) formatInvoice() as pure -> order as OrderLine <- rtn as String: `${order.quantity} x ${order.price} = ${calculateTotal(order)}` isValidOrder() as pure -> order as OrderLine <- rtn as Boolean: order.price? and order.quantity? and order.quantity > 0 defines program ExtractRecordDemo() stdout <- Stdout() order <- OrderLine(price: 29.99, quantity: 3, discount: 0.10, taxRate: 0.20) if isValidOrder(order) stdout.println(formatInvoice(order)) stdout.println(`Total: ${calculateTotal(order)}`)
Common mistakes
E11062 — A call with 4 or more positional arguments hides what each value means. Group the values in a record and pass them by name (or pass the record itself) - the names then document the call.
Incorrect:
order <- OrderLine(29.99, 3, 0.10, 0.20)
Correct:
order <- OrderLine(price: 29.99, quantity: 3, discount: 0.10, taxRate: 0.20)
Other ways to ask this
- How do I reduce repeated parameters across multiple functions?
- Should I extract a record when many functions share the same arguments?
- What is the idiomatic way to handle repeated function parameters in EK9?
Coming from another language?
Java: extract a parameter object or record. Python: use a dataclass. EK9: extract a record with default operator.
Keywords: arguments, extract, idiomatic, parameters, record, refactor, repeated