Any number of values
A handler can be called with more values than it names, or fewer. the paramCount says how many it was given, and param(n) gives the nth, named or not. A function that adds up whatever it is given:
function total
local tSum
put 0 into tSum
repeat with i = 1 to the paramCount
add param(i) to tSum
end repeat
return tSum
end total
put total(1, 2, 3)
put total(10)
put total()
6 10 0
A named parameter that was not given is empty, and extra values beyond the names are still there for param. the params shows the whole call, which is handy in a trace:
command showCall pA, pB
put the params && "with" && the paramCount && "values; pB is" && quote & pB & quote
end showCall
showCall "x"
showCall "x", 2, "extra"
showCall "x" with 1 values; pB is "" showCall "x","2","extra" with 3 values; pB is "2"
Values you may leave out
xTalk has no special syntax for a default value: test for empty, and fill it in at the top of the handler. Callers can then leave out the values that are usually the same:
function greet pName, pGreeting
if pGreeting is empty then put "Hello" into pGreeting
return pGreeting & "," && pName
end greet
put greet("Ada")
put greet("Ada", "Good morning")
Hello, Ada Good morning, Ada
Changing the caller's variable: @
A parameter is normally a copy: changing it changes nothing outside the handler. Put @ before its name and the parameter is the caller's variable, passed by reference, so the handler can change it. By custom such a parameter's name begins with r:
command addTax @rPrice, pRate
multiply rPrice by 1 + pRate / 100
end addTax
command addItem @rList, pItem
put pItem into rList[the number of elements of rList + 1]
end addItem
put 100 into tPrice
addTax tPrice, 20
put tPrice
addItem tFruit, "apple"
addItem tFruit, "pear"
put the number of elements of tFruit && tFruit[2]
120 2 pear
By reference is also quicker for big values: a large array passed with @ is not copied. Use it for that, or when changing the caller's variable is the whole point, as with addItem; otherwise a function that returns a new value is easier to follow.
Giving back several values
A handler returns one value, but the value can be an array with as many elements as you like:
function summary pList
local tResult
put min(pList) into tResult["lowest"]
put max(pList) into tResult["highest"]
put average(pList) into tResult["mean"]
return tResult
end summary
put summary("3,9,6,2") into tStats
put tStats["lowest"] && "to" && tStats["highest"] && "averaging" && tStats["mean"]
2 to 9 averaging 5
Reporting failure: return for error
xTalk's own commands report a problem in the result (Reading and writing files), and yours can too. return ... for error leaves the problem in the result, and the call's value empty; return ... for value gives back the answer and leaves the result empty. The caller checks the result straight after the call:
function safeDivide pA, pB
if pB is 0 then return "cannot divide by zero" for error
return pA / pB for value
end safeDivide
repeat for each item tDivisor in "4,0"
put safeDivide(10, tDivisor) into tAnswer
if the result is not empty then
put "10 /" && tDivisor & ":" && the result
else
put "10 /" && tDivisor && "=" && tAnswer
end if
end repeat
10 / 4 = 2.5 10 / 0: cannot divide by zero
A command works the same way, with its value in it:
command lookUpColour pName
switch pName
case "sky"
return "blue" for value
case "grass"
return "green" for value
end switch
return "no colour for" && pName for error
end lookUpColour
repeat for each item tThing in "sky,sea"
lookUpColour tThing
if the result is not empty then
put "problem:" && the result
else
put tThing && "is" && it
end if
end repeat
sky is blue problem: no colour for sea
Return for error suits problems the caller should expect and handle, such as a missing file or a bad value typed in. For a mistake that means the program itself is wrong, throw (Handling errors) is better: it cannot be ignored by accident.
Try it yourself
Write a command parseDate that takes text such as 2026-03-14 and puts its parts into an array passed by reference (keys year, month, day), or returns for error when the text is not three numbers joined by -. Try it on 2026-03-14 and 14 March.
Show a solution
command parseDate pText, @rDate
set the itemDelimiter to "-"
if the number of items of pText is not 3 then
return "not a date like 2026-03-14:" && pText for error
end if
repeat for each item tPart in pText
if tPart is not an integer then return "not a number:" && tPart for error
end repeat
put item 1 of pText into rDate["year"]
put item 2 of pText into rDate["month"]
put item 3 of pText into rDate["day"]
return empty for value
end parseDate
repeat for each line tText in "2026-03-14" & return & "14 March"
parseDate tText, tDate
if the result is not empty then
put "problem:" && the result
else
put "day" && tDate["day"] + 0 && "of month" && tDate["month"] + 0 && "in" && tDate["year"]
end if
end repeat
day 14 of month 3 in 2026 problem: not a date like 2026-03-14: 14 March
Words in this lesson
Each one finds every lesson that uses it. The Dictionary has the whole story of each, with its syntax and more examples.