Killer ValuesWalk Custom Function

Discovering ways to make software faster and more efficient brings a great amount of joy to developers. The reason behind this is simple: with enough experience, you come to realize that straightforward and simple code is much easier to maintain than complex and hard-to-maintain code. Self-contained code with fewer dependencies is both easier to understand and refactor.

In this video, I share one of my all-time favorite functions in Claris/FileMaker development, the Custom Function named CustomList. Although this function has served me well, it has now been surpassed in terms of speed and optimization by a newer method - the ValuesWalk function. This video demonstrates how you can utilize FileMaker's calculation engine to calculate the results you need and then seamlessly display those results within your user interface using the ValuesWalk function.

Moreover, the ValuesWalk custom function extends far beyond the simple use case presented. It can be employed to process any type of data, from generating ad-hoc delimited text files to processing simple lists. The ValuesWalk function is absolutely a valuable tool that every developer should be familiar with. With built-in performance testing, you can determine the optimal chunk size for processing the data you are working with. This knowledge is essential for advanced Claris/FileMaker development and is a must-know piece of information for developers aiming to optimize their solutions.

AttachmentSize
03-Invoice Solution-ValuesWalk.zip3.44 MB

Comments

I suspect it will take me a while to fully comprehend the power of this function. I'm excited to try it.
One question, Matt. Rather than throwing an error when the count is greater than the chunk_size, why not set chunk_size = min (~count, chunks)? If you know what the max size is, why not fix it instead of simple enforcement? Honest question.
Thanks for the cool function. I hope you point out other ways to use it in future videos.

The issue of where to address and where to throw an error is often a matter of preference. In this case, the chunk size vs the value count coming in could be determined prior to coming into the function.

I think, based on how I code, I tend to be defensive by default and would account for this prior to entering the function. But, if you lean towards the side of "never allow an error to happen" then you can certainly adjust the code to account for the condition within the function.

I'll probably end up revising the function at some point in time when this issue bites me. Thanks for making me thing about it. ;)

-- Matt Petrowsky - ISO FileMaker Magazine Editor

Matt, this is a great function to replace CustomList in many circumstances.

I too like the idea of adjusting chunk size to down to however many values remain (~count). Requires less error trapping outside of the function.

Question about this line:

~proceed = not IsEmpty ( ~values ) and ~validFunction and ~count > ~chunk_size;

Why would it not be:

~proceed = not IsEmpty ( ~values ) and ~validFunction and ~count >= ~chunk_size;

(i.e. ~count less than or equal to ~chunk_size instead of ~count less than ~chunk_size)

Assuming both ~count and ~chunk_size are zero-based, won't using > instead of >= fail if ~chunk_size is exactly the same as ~count? (and don't we want it to proceed if ~chunk_size is exactly the same as ~count?).

Maybe I'm missing something.

A small oversight: for tax calculation I think you should use Line Items::Line Subtotal

But the real first problem is that the Total Tax is wrong.
I believe the function calculates an item twice and I suspect this itam is the first
example:
Record no. 3
Tax = .2
Bike - Black $20
Steel Cassette $32
Bike Wheel $48
$ui.taxtotal: 120
It should be: 100

The second problem is that if there is only one record in Line Items, there is only the total, which is correct in this case

Sorry about that. I didn't debug that code. I was just throwing it in there to showcase the use of the function. If you actually wanted valid code then you would need to adjust it to something like this. For some reason, out-of-scope variable use is picking up the first value twice. Remember, trust, but always verify. Good thing you're doing that because I used the amount value instead of the line subtotal.

I would have to further debug the implementation to truely understand what is going on with the first value thing, but the solution code would be this.

Let ( [
	$$TAX.RATE = If ( IsEmpty ( $$TAX.RATE ) ; .0725 ; $$TAX.RATE );
	~amounts = List ( Line Items::Line Subtotal );
	$~description = List ( Line Items::Description );
	$ui.taxtotal = 0;
	$ui.taxes = ValuesWalk ( ~amounts ; "
					GetValue ( $~description ; $~n )
					& Char ( 9 )
					& \"$\"
					& Let ( [
							~tax = Round ( GetAsNumber ( $~value ) * $$TAX.RATE ; 2 );
							$ui.taxtotal = $ui.taxtotal + ~tax
					] ; ~tax )" ; 1 );
	$ui.taxtotal = $ui.taxtotal - ( GetValue ( ~amounts ; 1 ) * $$TAX.RATE )
];
	IsEmpty ( List ( Line Items::PrimaryKey ) )
)

P.S. Sorry about the code not indenting on the website properly. Something else to fix.

-- Matt Petrowsky - ISO FileMaker Magazine Editor

TY much for your answer.
I am very interested in this function and will try to debug it as soon as possible.
I'll start with the two problems:
Why does it loop once more? I put a counter in the function, right after the $ui.taxtotal calculation and indeed with 3 records it goes 4 times.
Why if there is only one record, even if my counter correctly marks 1, does it not display the product and taxes?

Gianandrea

Also to add some historical accuracy to the lessons HOnza learned about chunking: One of the biggest optimizations that HOnza added to the demo he provided came from Josh Willing Halpern. His input in those lessons was legendary. ;)

Josh Ormond

Love this function, but I have a simple Simple Question.

Here is myList =
F05BCE16-E78E-4F53-840E-8A2CC8E517A5 & "¶" &
E0815646-1B81-4D20-A2A9-916CDC7FB96C

This $~value function will return this whole list, which is useful for sure. But, I want to just grab each item, store it and move on down myList . Context: I want to use the UUIDs in this list as ids tag in a webviewer.

The function reserves two special variables $~value and $~n. You should not use them as declarations, meaning declared as part of a Let within the function passed into the custom function. You can reference them to process the list of data. Here's an example with the two values you provided where it extracts only the first 8 values.

Let ( [
	~list = List (
		"F05BCE16-E78E-4F53-840E-8A2CC8E517A5";
		"E0815646-1B81-4D20-A2A9-916CDC7FB96C";
		get ( uuid );
		get ( uuid );
		)
];
	ValuesWalk ( ~list ; "Left ( $~value ; 8 )" ; ValueCount ( ~list ) - 1 )
)
Result
F05BCE16
E0815646
E47465E3
AB324289

If you want to see that each value is getting processed individually you can store them into a variable repetition.

Let ( [
	~list = List (
		"F05BCE16-E78E-4F53-840E-8A2CC8E517A5";
		"E0815646-1B81-4D20-A2A9-916CDC7FB96C";
		Get ( UUID );
		Get ( UUID );
		)
];
	ValuesWalk ( ~list ; "Let ( $$STORED[$~n] = $~value ; 1 )" ; ValueCount ( ~list ) - 1 )
)

-- Matt Petrowsky - ISO FileMaker Magazine Editor

Matt, this really adds to the video content. The way you are using the chunking parameter in your response ... would not have figured that one out right away. Again thank you for your response. (So many more uses for this CF.)