Creating a Simple Pushdown Stack

I used to have a macro(s) that handled stacks and queues of strings for me. But that was before subroutines existed. Now that subroutines exist, which can return variables, it would be even simpler to do.

In fact, one of the parameters my routines accepted was the name of the queue or stack. So it was one macro that handled all queues and stacks by passing the name as one parameter.

Hi Rob. Jim is right, I'm PREpending new entries at the top of the list. It's a most recent list.

In your example list of "Ocean ... Echo", "Ocean" would be the most recent addition, so to truncate to the most-recent 10, I'd use head -10.

Yep, and I tend to use appending, hence why I went backwards :).

-rob.

Generally, for variables, yes that is correct.

A variable that does not exist is obviously empty, and a variable that has a value obviously exists.

So the only interesting case would be a variable that exists but is empty. However setting a variable to empty deletes it (from the engine’s perspective, the editor may still know about the variable in other ways).

Thanks for the tips on further simplifying my already pretty simple macro.

That suggests my basic subroutine can be simplified to simply deleting any literally matching line that currently exists, which does not require that the variable exist or be non-empty, and then prepending the line to the variable, which again does not require that the variable exist or be non-empty.

I could also prevent the list from growing too long without having to filter any line counts or evaluate any conditionals simply by adding a third action that deletes the 21st (or whatever) entry, if there is one.

The third action is new to v11 and the trigger for the whole subroutine (not shown) is the Space Changed trigger, which is also v11.

2 Likes

Is there a way to delete the line and the %Return% delimiter in one step? This action:

image

leaves an empty line, I think. I suppose that I could add a second action to look for empty lines and delete them, but I'd love to do it all in one step.

Any ideas?

The shell command "grep ." deletes all empty lines from a file or variable, like this:

image

1 Like

That requires initiating a shell. I'm hoping to do it all in one command, deleting the content of the line along with the %Return% delimiter, but haven't come up with it yet.

Right now, this is what I have, all KBM built-in actions, without (I hope) having to initiate a shell:

image

Just curious, why is that a problem? It will take .002 seconds or so to execute, so it won't slow your macro in any meaningful way. Why the aversion to a shell/desire to do it in one command?

-rob.

Because it's part of a sequence that happens every time I change Desktop Workspaces and which sometimes can take as long as 2 sec, it seems -- which is long enough that I get where I'm going and start to read, work, find my place, etc. when >>POP<< comes the notification that I'm in the new workspace and all is right with the world. That's annoying. I'm trying to improve it.

If that notification happens in about 1/2 sec, then my experience is simply a flow of: I change Spaces, I get the notice that I am where I want to be, I go on. Calm, reassuring, comfortable.

So I'm looking at what I can shave off. I can see what that 0.5 - 1.0 sec feels like if I leave out all kinds of housekeeping, error conditions, and stuff that makes a difference elsewhere, or predefine things for testing that have to be queried for in reality, which I don't want to do or can't do on a regular basis. So I'm exploring what I can tighten up.

To find out where the time is going, you might try timing some of the routines—my MultiTimer macro does just that, and lets you get subtotals just by inserting calls wherever you need them. You might be surprised to find where the time is going. I know I was when I worked on optimizing my biggest time-consuming macros.

-rob.

Sounds good. Thanks. (Just what I need, a branching rabbit hole.)

1 Like

What's wrong with this picture?

I made the erroneous assumption that the initial Set Variable action would somehow only execute IF there already was an Item #21 in the list. Silly me. When does KBM ever require variables to exist before they can be set?

So what does it do? It adds enough delimiters to the end of the list to create an Item #21 and then it sets that to the supplied text, which in this case is empty.

And the second action deletes approximately half of the added items, changing each pair of Returns to a single Return.

So the number of blank lines that was added was not entirely consistent and the resulting length of the list was not entirely consistent -- and it only happened the first time a shorter list got accessed, then no further changes were made, mostly. A bit difficult to debug until the Ah-Ha!

So truncating the list will require a slightly different approach. Later ...

1 Like

Just in case you have forgotten, with KM the zero element of any array ([0]) contains the current size of the array, so you can tell beforehand how many items there are. So if

GlobalRecentDeskSpaces[0]\r

Is equal to 21, you know it's safe to "delete" that element. The trouble is, the way you are deleting the last element isn't reducing the size of the array, so to do that you need to trim off the last \r from the variable.

BTW (apropos your remark about variables existing)

GlobalRecentDeskSpaces[21]\r

is not really a variable - it's an array element and it behaves like a variable. What is a variable is this:

GlobalRecentDeskSpaces

YES! I had indeed forgotten. I had been looking at Filtering the variable with a Line Count filter. But the filter will actually go through and count the lines, one by one. The [0] syntax refers to a value that is already automatically there, and therefore will execute marginally faster.

Thank you!

Pardon the sloppy terminology, I was trying to point out my sloppy thinking and the erroneous assumption that lead to a bug that was hard to find.

Yes, it behaves like a variable and KBM will assign a value to the array element, within the existing variable, even if that array element does yet exist. If the array is not long enough, KBM make it long enough in order to be able to assign the value.

I just did a simple test of how KBM handles this:
image

The variable did not exist before I ran this action using the Try button.

Here is what I got:
image

There are 24 commas in that string, as delimiters for 25 array items.

In another thread somewhere here, Peter explains that this is expected ... a coming update (maybe the one that just came out?) will limit it to creating 100 elements, if I recall correctly.

-rob.

Peter mentions that here

I remarked on the extension of an array if you write to a non-existing element in my post

Yes, I think it should definitely be expected, I just didn't think it through and when I figured it out it was a "Doh!" moment.

I read that post and at this point I guess it seemed so obvious, at the moment that I read it, that it didn't stick.

1 Like

Another BUG in the previous pushdown stack subroutine, with a simple fix:

Using the Preferences > Variables window I started seeing a final entry in the list that consisted of one long string of every item, with no delimiters, just 8, 12, 20, or whatever items run together as a single item. WTF? Except for that, it's been doing it's job, in the background, mostly being used to switch to the previous desktop.

I was contemplating creating a log that would have entries every time the variable changed so that I could match up when it happened to the KBM Engine log and have a clue. Then in adding comments to the subroutine, to walk through how it works, I found the answer. It's in the removal of the new item from its previous place in the list.

image

I realized that if the variable theNewDeskSpaceID was empty (or non existant) then this would do exactly what I was seeing. It would remove every Return from the variable. Then the next time the subroutine was called, new entries would be added to the front, and this would stay at the bottom of the list.

Wrapping it in an If/Else seems to have done the trick.

image