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.Satorres6134 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.

A little bit more detail. The queries in %SYSTEM.License are not defined as [SqlProc]s. Therefore, they can't be called from outside IRIS, including from Python. To get the information returned by these queries in Python, you should write your own method in ObjectScript, that runs the query with the (deprecated) %Library.ResultSet class. As you loop through the results:

Ah, I misinterpreted "this alias" in your post! So you meant (I added italicized text): "I like to define :sql as a way to launch the shell and execute a statement - so that means this built-in :sql alias should be renamed by InterSystems to something else!! or be removed."

At least aliases defined in .iris_init override any built-in aliases.

Here's some info that was inadvertently removed from the docs, but will be returning soon:


On Unix systems, if a file named ~/.iris_init exists, it is read when a terminal session is initiated. Only lines starting with :<command> are processed. All other lines are ignored. This file accepts only :alias commands, which enables you to store favorite command abbreviations there.
Example of a ~/.iris_init file:

# Initial aliases
:alias %  zn "%SYS"
:alias load Do $System.OBJ.Load("$1",$S("$2"="":"ck",1:"$2"))
:alias ut Do ##class(%UnitTest.Manager).RunTest("$1")

Nice article about an important question: when should you touch the storage definition? Some comments on the scenarios (with sound effects!). The only modifications I'd make to the bookshelf analogy is that there are gazillions of shelves (every person gets their own shelf) using the mapping of what type of book goes in each slot.

  1. Scenario 1: You are creating a class, and adding, deleting, and renaming properties. If there's any data for the class, it is test/temporary data and can be deleted at will. As Vivian saw, deleting a property doesn't change the storage definition (the slot for the deleted property is left unused), and renaming a property is really a deletion (old slot unused) followed by an addition (new slot). Once you get the class the way you want it for release, you can safely delete the storage definition (since there's no real data) and the next compilation will create a fresh one, with no unused slots. No danger (cue happy music).
  2. Scenario 2: You are editing an existing class with real stored data. If you rename any property (new or existing, with or without data) it's best practice to rename the storage definition slot also before your next compile. If it's a newly added property without data and you don't bother to rename the slot, it's OK, but you now have a wasted slot that will never be used, and a new slot for the data you'll eventually start saving. Why not rename the slot right away? On the other hand, if it's a property that has data, you must rename the storage slot, or the data for that property will no longer be accessible, and new data for the renamed property will go in a different slot. Any danger is prevented by renaming the property and storage definition slot at the same time (cue triumphant marching music).
  3. Scenario 3: You delete a property with real stored data. As before, the old slot is left unused. Any new property added later will not use that slot (no double-booking; new data won't ever be added there). But the real question is: Why are you deleting the property? Do you not care about that data anymore? If so, why aren't you deleting the data first? And by deleting the data, I don't mean editing the global directly (which I think is what Vivian meant by "don't do this."). But it's not dangerous to the table to use SQL to delete Book B from every bookshelf before deleting the property:update schema.table set property = null(cue computer bleeps).

Editing the name of any unused slot in the storage definition and adding "-unused" to make things clear could be OK but it's definitely not intended for that use. I'm not sure it's necessary to do anything in this case; If I see a slot in the storage definition named XYZ and there's no property XYZ, I know it's an unused slot. Maybe preceding the storage definition with a comment section would be cleaner:

/* unused slots
   XYZ (as of 1/1/2020)
   ABC (as of 6/1/2021)
*/

Please let me know if it's not clear, or if I missed a scenario.

Very strange! I was never on the standards committee. I started using MUMPS in 1987, and I remember it differently ($next being replaced by $order). Let me check the archives...

  • My 1981 copy of the Standard MUMPS Pocket Guide states that variables can have only non-negative integer subscripts, and lists $next (returning -1 if no more subscripts exist), but there's no mention of $order.
  • My 1983 copy of the Pocket Guide (based on the 1977 ANSI Standard) states that variables can use any string as a subscript and lists $order (both noted as approved extensions of the Standard; $order using "" as both the seed and the flag for no more subscripts), and $next is still listed.
  • My 1987 copy of the Pocket Guide (based on the 1984 ANSI Standard) has the same info as the 1983 Guide, except the approved extensions are now part of the Standard.
  • My 1995 copy of the Pocket Guide (based on the 1995 ANSI Standard) lists the 2 argument form of $order, but $next (having been deprecated) is not listed.

Public viewing of the Solon Archives available by appointment only ;-)

https://www.youtube.com/watch?v=rIz_xhYK2Mo

All I can say is Wow! I experienced many of the same things over my career, but I was living in safe, protected, training-room-land, not the real world of development like Nigel. Great article!

I'll just note that Nigel says "might" in the title. laugh

One thing that confused me, Nigel. You wrote "If one of the early MUMPS creators had called $order "$next", it would immediately be recognizable as Next()...". But I know that you know that the original $order was called $next.