Need help & advice: Confused by cond: macro

Hi I am using Harlowe version 2.3.12 and am confused by the behavior of the cond: macro. Here’s a simple piece of code that demonstrates my confusion. I want the macro $getFirst to return the first element of an array of numbers but, if the input array is empty, to return the value 0,

(set: $getFirst to (macro: array-type _v, [
(set: _output to (cond:
_v’s length is 0, 0,
(1) of _v))
(output-data: _output)]))

When I run this with _v as the empty array I expect it to detect that _v has length 0 and to return 0 before it tries to find _v’s first element. But instead it gives me an error because _v does not have a first element.

In contrast, when I replace the default output of cond to a fixed value just to test it, it works and returns the right value before reaching that condition. So this condition correctly returns 0 when given the empty array, even though it is exactly the same up to and including the condition testing true.

(set: $getFirst to (macro: array-type _v, [
(set: _output to (cond:
_v’s length is 0, 0,
1))
(output-data: _output)]))

I’d like to understand what is happening here. Also, if anybody knows an easy way to get a macro to return the first member of an array, but not to return an error for the empty array, please tell me!

This hack does what I want, but I’d prefer something simpler/more general. And I still don’t understand exactly what is happening when cond: executes.

(set: $getFirst to (macro: array-type _v, [
(set: _x to (cond:
_v’s length > 0, _v,
(a:0)))
(set: _output to _x’s 1st)
(output-data: _output)
]
)
)

Please use the comment field’s Preformatted text option when including code examples in your comments, it makes the code easier to copy-n-paste and stops the forum’s software converting valid standard single & double quotes into invalid typographical (curvy) equivalents.

It appears that the (cond:) macro evaluates all of the expression being passed to it before the macro itself is called.

eg. when your (cond: _v's length is 0, 0, (1) of _v) is about to be executed the _v's length is 0 and (1) of _v expressions are both evaluated before the results of those evaluations are passed to the (cond:) macro. And in the case where the _v array has no elements the (1) of _v expression will cause an error because that expression is trying to access the 1st element of an array that has no such element.

In your use-case you would be better off defining your ($getFirst:) macro like so…

(set: $getFirst to (macro: array-type _v, [
	(if: _v's length is 0)[
		(output-data: 0)
	]
	(else:)[
		(output-data: _v's 1st)
	]
]))
1 Like

Thanks a lot! That also solves a different problem I was having, which was getting info out of an if hook (the reason I was using cond: in the first place). It appears output-data works, even though setting local variables in the hook fizzles.