What's the proper way to check for non-existent `Tab` to prevent error?

While clickData.func.desttab or clickData.func.sourcetab.lister.desttab, when available, are of type object (checked with typeof), they are the value 0 of type number instead when being non-existent under certain circumstances. (Also, the default value of a Tab object seems to be an ID, which is numeric.) But I didn't saw this behavior documented anywhere! (So, these docs and others are incomplete in at least the "Return Type" column.)

When you call Command.SetDestTab() with that 0, the function throws. So, this must be avoided.

What is the recommended, supported way of verifying that a tab property contains an actual Tab object? I'm currently doing if (tab.lister != null) (!= null also checks against undefined), just to be sure, because the type number without this being documented is a little suspect to me.

Maybe, the tab properties should rather return undefined/null for a non-existent Tab?

Hi.
As far as I know, there are plenty of ways to check if a tab is a candidate for use with Command.
It looks like you're getting the tab from a Lister, so you can use something like this:

var desttab= lister.desttab;
DOpus.Output(desttab && desttab.path ? desttab.path : 'no valid dest tab');

So by checking both desttab && desttab.path, you can ensure that desttab has a path.

Also you'll probably notice that if you use DOpus.TypeOf() with a non existent tab you' ll get int instead of object.Tab.

Probably is better to use DOpus.TypeOf() to check for DOpus objects instead of the general typeof, but that's just my opinion.

I didn't know of DOpus.TypeOf(). That's useful.

Coming from Rust, I like it explicit, though. This is why I'd favor tab != null (differentiation between null and undefined doesn't have do be explicit, because it's a JS quirk). I find something like tab && tab.path too ugly, unintuitive and too much relying on dynamism for my taste.

So, my question could be refined:

  • Is there hope of the tab properties yielding undefined/null instead of 0?
  • Otherwise, could 0 of DOpus type int be documented and guaranteed to be the non-existent-value? (I don't know why that should be the case, though. Would be a strange non-existent-value.) Then, you could do if (tab !== 0) (meh!) or if (DOpus.TypeOf(tab) === "object.Tab") without a fear of your code breaking.

FWIW, if (tab) would cover checks for null, undefined and 0 as a value in Jscript (which I believe is the main target language). So IMHO it's pointless for an invalid tab to return undefined

Also, I don't think a tab with an HWND of '0' could exist, so I'm not sure what you mean by breaking your code, sorry. —if (tab) should cover everything.

:+1:

How can you just say these numbers are HWNDs in passing, as if it must be common knowledge? When I search for "hwnd" in the docs, a mention of %tab_hwnd% is the only occurrence I find, which doesn't associate it with the numbers I talked about and is just irritating on its own without further explanation. I could only confirm that the Tab default values are dopus.filedisplaycontainer HWNDs using a spy tool.

The discrepancy between object.Tab and int stays. So, you have a Tab's default value, which definitely is an HWND, on the one hand, and the int 0, which can be interpreted as HWND NULL, on the other hand. The worst is that this is not documented.

Minds work differently. I said I like it more explicit, not least for consistency reasons with other cases.

If I may, sir, you are being very picky.
You're asking for a proper way to check something, and are given several options (DOpus.TypeOf, if (tab)) but they're not good enough for your taste or your minds.
You advocate coming from another language (which by the way is a compiled language, not a scripting language) ... I do too and can not say I'm always pleased by the ways JScript is sometimes leading me too.
But that's what we have here with MS and Opus integration, and even if sometimes its looks are not the most explicit, they already have the great advantage to exist and you may have to accept some trade offs.

Let's not forget we're talking about scripts to manage files, we're not building the next Information System for NASA ... so, even if you seem to be onto building something quite complex (and which seems promising and usefull to at least parts of the users), you might have to go with some compromises, or you'll end up very frustrated.
Just my two cents and personal opinion, which I have no doubt you won't fully agree to say the least :slight_smile:

Pickiness to some extent is part of my personality. :wink: I wouldn't call it picky, though, to wish that the exact behavior was at least documented. It's a fact that the docs talk about a Tab object being the property type, when, in fact, the type can also be int.

I didn't say anything against if (tab) being generally in use. Others' code isn't my code. I just have a tendency against it to use it myself, because it seems so open-ended to my mind, and I benefit from orienting myself towards principles that I form rather than thinking about every new case again. But I think that reading more than the title conveys that I was up to exact checks. (The Rust context really helps me, because I can grasp things much more readily, which is really great. So, I like that experience elsewhere also.)

That the tab properties could be switched to returning undefined/null instead of 0 was always just a question that I would've liked a take on by the DOpus devs. It may not be desired because of possible compatibility problems. But then again, this would imply that explicit checks are valid and could've already been written by some people, right?

Didn't I say DOpus.TypeOf() is useful and produced an example with it?

This was about having no guarantee how this specific API surface behaves. If you write if (DOpus.TypeOf(tab) === "object.Tab"), and, in the case of a non-existent tab, DOpus were to return a Tab object in the future whose default value is 0, the check would fail, because it assumes that the non-existent-value is of another type than object.Tab.

As a workaround for all of this, the alternative if (Number(tab) !== 0) just came to my mind, which is quite explicit and nicely converges the types object.Tab and int. (I already use type constructors in other cases to transform DOpus objects to JScript types.) But it's just a workaround. (Again: This is just about forming principles to work with the old JScript language in a way that I grew to like while working with more modern languages. And these things are always interconnected, so it's ultimately not only about trivial single case.)

if (tab) is what you'd normally do in JScript to test if an object exists and is valid, and all you should need here. No reason to overthink things beyond that.