Hi folks!
Sometimes, when designing a class method and feeding it with more and more useful features, very soon the number of parameters can reach 10 and even more.
It becomes pretty difficult for users of useful methods to remember the position of the important parameter, and it is very easy to misuse the position and transfer the wrong value to the wrong parameter.
Here is an example of such a method (I asked GPT to create a method with 20 params):
ClassMethod GenerateReportWith20Params(
pTitle As %String = "",
pAuthor As %String = "",
pDate As %String = "", // e.g. 2025-09-03
pCompany As %String = "",
pDepartment As %String = "",
pVersion As %String = "1.0",
pFormat As %String = "pdf", // pdf|html|docx
pIncludeCharts As %Boolean = 1,
pIncludeSummary As %Boolean = 1,
pIncludeAppendix As %Boolean = 0,
pConfidentiality As %String = "Public",
pLanguage As %String = "en",
pReviewers As %String = "", // CSV, e.g. "Alice,Bob"
pApprover As %String = "",
pLogoPath As %String = "",
pWatermarkText As %String = "",
pColorScheme As %String = "default",
pPageSize As %String = "A4",
pOrientation As %String = "Portrait",
pOutputPath As %String = "report.pdf"
) As %Status
{
// implementation
}
Beautiful, isn't it?)
And here is an example of using it, providing only 1,2,5,13,19 params:
Do ##class(Report.Generator).GenerateReport(
"Annual Financial Report", // 1: pTitle
"Jane Doe", // 2: pAuthor
,, // 3–4 skipped
"Finance", // 5: pDepartment
,,,,,,, // 6–12 skipped
"Alice,Bob", // 13: pReviewers
,,,,, // 14–18 skipped
"Landscape" // 19: pOrientation
// 20 (pOutputPath) omitted -> default used
)
A soup of commas.
There are, of course, many ways to mitigate the problem. E.g., this is where JSON approach can help. I found its usage in the very useful @Benjamin De Boe's bdb-sql-utils lib e.g. here, where qualifiers are being provided as JSON and then parsed inside a method:
do ##class(bdb.sql.InferSchema).BuildAll("/tmp/data-dump/*.csv", { "verbose": 1, "targetSchema": "MySchema" })
I like it and leveraged the same approach in csvgen lib, and introduced the Gen() method, which is an alias to Generate(), but which accepts reasonable 6 parameters instead of 11. Indeed:
Generate signature:
/// generates class for an arbitrary CSV. All the properties are VARCHAR 250
/// fncsv - csv file on disk
/// dlm - delimeter
/// pguessTypes - flag to try to guess on datatypes
/// pclass - class name, if not passed, then will be generated and returned by ref
/// recordCount - amount of records created and returned byRef
/// pverbose=1 - 1 if you want utility to comment to terminal what is going on
/// pappend=0 - 1 if you want to add records to already existing
/// ploaddata=1 - use LOAD DATA if it is avaliable
/// pheader=1 - if equals 1 import skips the 1st row that is considered as header
/// pkey - if non-empty, then will consider to introduce a primary key for a column with the pkey name
ClassMethod Generate(fncsv As %String, dlm As %String = ",", ByRef pclass As %String, ByRef prowtype As %String, pguessTypes As %Boolean = 1, Output recordsCount As %Integer, pverbose As %Boolean = 1, pappend As %Boolean = 0, ploaddata As %Boolean = 1, pheader As %Boolean = 1, pkey As %String = "") As %Status
Gen signature:
/// do ##class(community.csvgen).Gen("/tmp/data-dump/file.csv",,"package.class",,{ "verbose": 1, "guessTypes": 1, "append": 0, "LoadData": 1, "header": 1, "primaryKey": "colname" },.recordsCount)
ClassMethod Gen(fncsv As %String, dlm As %String = ",", ByRef pclass As %String, ByRef prowtype As %String, qualifiers As %String = "", Output recordsCount As %Integer)
Inside the method, JSON is being parsed to a key-value variable, which provides a convenient way to proceed with qualifiers:
ClassMethod FlattenQualifiers(ByRef qf, obj As %DynamicObject, prefix As %String = "") [ Internal, Private ]
{
set iterator = obj.%GetIterator()
while iterator.%GetNext(.key, .value) {
set sub = $s(prefix="":$$$LOWER(key), 1:prefix_"."_$$$LOWER(key))
if $isobject(value) {
do ..FlattenQualifiers(.qf, value, sub)
} else {
set qf(sub) = value
}
}
}
And this is an example of how it can be used, e.g., when Primary needs to be introduced:
Generate call:
set status=##class(community.csvgen).Generate(fn,",",.pclass,.prowtype,1,.tResults,,,,,"name")
I need to type 5 commas before a necessary parameter can be placed.
Gen call:
set status=##class(community.csvgen).Gen(fn,",",.pclass,.prowtype,{"verbose":1,"primarykey":"name"},.tResults)
Here, I provide only the qualifiers I need, and it is clear which are provided. That's why I want to share the experience with you, amazing InterSystems Developer Community!
Thanks again to both @Benjamin De Boe and JSON for making life simpler for developers with ObjectScript!
Happy coding!