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
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
E11031 — Single-letter parameter names hide their purpose. Extract a record with descriptive field names and pass that instead.
Incorrect:
calculateTotal() as pure -> p as Float, q as Integer, d as Float, t as Float <- rtn as Float: p * q
Correct:
calculateTotal() as pure -> order as OrderLine <- rtn as Float?
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: idiomatic, repeated, refactor, parameters, record, extract, arguments