Anything can be achieved without instance methods. The point here is that instance methods exist in object-oriented systems because they are considered a good, straightforward way to achieve certain things. In the case of unit tests sharing information using properties, that approach saves you from having to pass info around as method arguments, or declaring a list of public variables.

I've also used Studio for 20+ years. I can still remember how much better it was than what we had before. We can all still use Studio if we want; it's not a forced divorce. But we hope that VS Code -- ObjectScript's features will make you comfortable enough to decide to do a conscious uncoupling. And as Frank Sinatra sang: "Love's much lovelier, the second time around." And he could have sung that at the Diplomat Hotel in Fort Lauderdale in 1974, where coincidentally InterSystems is hosting our Global Summit this year!

Why are unit test methods instance methods? Since a running unit test is an instantiated object (%RegisteredObject), the unit test class itself can have custom properties, and the instance methods can use those properties as a way to share information. For example, initialize the properties in %OnBeforeAllTests(), and then access/change the properties in the test methods. 

@Nicholai Mitchko's example above is Python calling an ObjectScript method that has pass-by-ref arguments, and that works as he described. I wondered if Python methods could be written to return values in their arguments, despite the fact that Python doesn't have pass-by-ref arguments. The answer is "yes," but only if the caller passes in a data structure (like a list or a dict) that the Python method modifies. Otherwise, arguments to a Python method called from either ObjectScript or Python can't return values.

If you make a loooonnnnng $piece-delimited string, and a lonnnnnnnnng $list, and you loop 1000000 times, accessing random pieces and random $list items, and sum up the time, and divide by 1000000, you'll find that for access, $lists are faster than delimited strings. At least that's what I saw when $list first appeared. But my mentor from that time said "Yes Joel, they are faster, but $list was added to ObjectScript so that we wouldn't have to worry anymore about delimiters, and sub-delimiters, and sub-sub-delimiters, etc."

True. I personally am not a fan of using #dim in any way other than:

#dim variable as objectclassname

because it makes it clear that #dim provides code completion for object variables, which is the functionality I care about. Yes, I know it also provides variable documentation for developers who are used to declaring datatypes in other languages

The other documented options:

  • #dim variable as objectclassname = initialvalue (ok, but I prefer #dim followed by set)
  • #dim variable = initialvalue (there's no reason to use #dim to do what set does)
  • #dim variable as non-objectclassname (this is documentation only; no code completion is provided)
  • #dim variable as list/array of objectclassname (again, documentation only; no code completion)

It's not a big difference between Studio and VS Code - ObjectScript here. Studio automatically does the #dim for you when you do a %New() or %OpenId(), and VS Code - ObjectScript doesn't. But #dim is still necessary in both IDEs for referenced or returned objects:

set person = ##class(Simple.Person).%New()  // Studio WILL provide code completion for person, VS Code WON'T

#dim address as Simple.Address  // without #dim, neither Studio nor VS Code will provide code completion for address

set address = person.Address 

#dim rs as %SQL.StatementResult

set rs = statement.%Execute(args)  // you'll get code completion for rs thanks to #dim

Thanks Michael.

You could code it the oop way, and use $sortbegin on all the index globals for your multiple tables, which means you'd have to know or look up what the index global names are (since they're not always ^D and ^I anymore), and test 1000000 inserts (main table and referenced tables) with the index build deferred to the end, and time it to see how long it takes. 

And then code it the sql way, inserting the same data into the multiple tables using %NOINDEX, and calling %BuildIndices() on all the classes at the end, and time it to see how long that takes. The sql way is supposed to be faster...

@Alex Woodhead Why are you using $sortbegin on the ^D global? Just to show it's possible in this demo? Or are you recommending that general approach? It seems to me that the solution to the original question would be allowing the data to save normally (not using $sortbegin on the ^D global), and using $sortbegin on the ^I global and discarding those updates.
@Michael Fortunato Please tell us the reason for wanting to do this. It can't be that you want the index to be permanently out of sync with the data. Perhaps it's for performance for many inserts? If so, switching to a SQL approach with %NOINDEX (as @David Satorres suggested) is a good idea.

So this thread has clarified that the transaction that you read about in the docs is the transaction inside %Save(), and %OnSaveFinally() is a callback for %Save(). Your original question seems to be asking if the TCOMMIT command itself triggers a callback, but it doesn't. You could of course add your own code right after the TCOMMIT, but I guess that's not what you're looking for with this question.