Question
· Apr 16, 2023

Dissecting an OREF

When an object is created in memory, the object reference (OREF) is represented as a string value when displayed with the Write command:

HICG>Set pat=##class(JD.Sample.patient).%OpenId(70)
HICG>Write pat
1@JD.Sample.patient ; "stringified" OREF
HICG>Zwrite pat
pat=1@JD.Sample.patient  ; <OREF>
+----------------- general information ---------------
|      oref value: 1
|      class name: JD.Sample.patient
|           %%OID: $lb("70","JD.Sample.patient")
| reference count: 2
+----------------- attribute values ------------------
|       %Concurrency = 1  <Set>
|            address = "4 Foo St"
|               city = "Springfield"
|                dob = "2001-02-19"
|              email = "johndoe.fakeemail.fake"
|          firstname = "John"
|           lastname = "Doe"
|             mobile = "617-555-1212"
|                mrn = 124124
|               name = "John Doe"
|              phone = "617-555-0501"
|              state = "MA"
|                zip = "01234-5678"
+-----------------------------------------------------

Given the string "1@JD.Sample.patient," is there a way to convert that back to an OREF? I realize there is a variable that is specifically assigned as this object, but is there any way to manipulate the string representation to access the object's properties/methods?

This isn't a problem that necessarily needs a solution. I'm just wondering what the individual elements of the string represent; the last is obviously the classname, but what does the n@ indicate/describe, and can it be used along with the classname to assemble an OREF to the object?

Product version: IRIS 2022.2
$ZV: IRIS for UNIX (Ubuntu Server 22.04 LTS for x86-64) 2022.2 (Build 368U) Fri Oct 21 2022 17:15:06 EDT
Discussion (14)1
Log in or sign up to continue

@ is just a separator
while n is just an internal sequence number within your partition
see this example

SAMPLES>s a=##class(Sample.Person).%OpenId(2)
SAMPLES>s b=##class(Sample.Person).%OpenId(12)
SAMPLES>s c=##class(Sample.Employee).%OpenId(111)
SAMPLES>s d=##class(Sample.Company).%OpenId(9)
 
SAMPLES>zw
 
a=<OBJECT REFERENCE>[1@Sample.Person]
b=<OBJECT REFERENCE>[2@Sample.Person]
c=<OBJECT REFERENCE>[3@Sample.Employee]
d=<OBJECT REFERENCE>[4@Sample.Company]
SAMPLES>

you just can copy an already existing reference  SET rerf=a from the example above


to show all open objects:
Do $System.OBJ.ShowObjects()
Oref      Class Name                    Ref Count
----      ----------                    ---------
1         Sample.Person                 1
2         Sample.Person                 1
3         Sample.Employee               1
4         Sample.Company                1

 

OR

Do $System.OBJ.ShowObjects("/detail=1")
Oref      Class Name                    Ref Count
----      ----------                    ---------
1         Sample.Person                 1
+----------------- general information ---------------
|      oref value: 1
|      class name: Sample.Person
|           %%OID: $lb("2","Sample.Person")
| reference count: 1
+----------------- attribute values ------------------
|       %Concurrency = 1  <Set>
|                DOB = 32225
|               Name = "Ubertini,Brian S."
|                SSN = "231-12-5250"
+----------------- swizzled references ---------------
|   i%FavoriteColors = ""  <Set>
|   r%FavoriteColors = ""  <Set>
|             i%Home = $lb("9177 First Court","Bensonhurst","SC",42658)  <Set>
|             r%Home = ""  <Set>
|           i%Office = $lb("260 First Place","Larchmont","NV",99593)  <Set>
|           r%Office = ""  <Set>
|           i%Spouse = ""
|           r%Spouse = ""
+--------------- calculated references ---------------
|                Age   <Get>
+-----------------------------------------------------
 
2         Sample.Person                 1
+----------------- general information ---------------
|      oref value: 2
|      class name: Sample.Person
|           %%OID: $lb("12","Sample.Person")
| reference count: 1
+----------------- attribute values ------------------
|       %Concurrency = 1  <Set>
|                DOB = 33423
|               Name = "Waal,Jeff V."
|                SSN = "137-61-1656"
+----------------- swizzled references ---------------
|   i%FavoriteColors = ""  <Set>
|   r%FavoriteColors = ""  <Set>
|             i%Home = $lb("3872 Washington Place","Newton","NJ",80886)  <Set>
|             r%Home = ""  <Set>
|           i%Office = $lb("4339 Second Drive","Albany","PA",79202)  <Set>
|           r%Office = ""  <Set>
|           i%Spouse = ""
|           r%Spouse = ""
+--------------- calculated references ---------------
|                Age   <Get>
+-----------------------------------------------------
 
3         Sample.Employee               1
+----------------- general information ---------------
|      oref value: 3
|      class name: Sample.Employee
|           %%OID: $lb("111","Sample.Employee")
| reference count: 1
+----------------- attribute values ------------------
|       %Concurrency = 1  <Set>
|                DOB = 50109
|               Name = "Yezek,Chelsea F."
|                SSN = "227-72-8394"
|             Salary = 69426
|              Title = "Executive WebMaster"
+----------------- swizzled references ---------------
|          i%Company = 2  <Set>
|          r%Company = ""  <Set>
|   i%FavoriteColors = ""
|i%FavoriteColors(1) = "Blue"
|i%FavoriteColors(2) = "Yellow"
|   r%FavoriteColors = ""  <Set>
|             i%Home = $lb("7573 Main Drive","Bensonhurst","MA",97453)  <Set>
|             r%Home = ""  <Set>
|            i%Notes = ""  <Set>
|            r%Notes = ""  <Set>
|           i%Office = $lb("7403 Oak Place","Vail","NH",46047)  <Set>
|           r%Office = ""  <Set>
|          i%Picture = ""  <Set>
|          r%Picture = ""  <Set>
|           i%Spouse = 89
|           r%Spouse = ""
+--------------- calculated references ---------------
|                Age   <Get>
+-----------------------------------------------------

4         Sample.Company                1
+----------------- general information ---------------
|      oref value: 4
|      class name: Sample.Company
|           %%OID: $lb("9","Sample.Company")
| reference count: 1
+----------------- attribute values ------------------
|       %Concurrency = 1  <Set>
|            Mission = "Leaders in dynamic nano-application development instruments for the desktop."
|               Name = "BioDyne LLC."
|            Revenue = 928565856
|              TaxID = "X6668"
+----------------- swizzled references ---------------
|        i%Employees = $lb("Sample.Employee","Company",4,"many",1,1)  <Set>
|        r%Employees = ""  <Set>
+-----------------------------------------------------
  

Then you can use %%OID to generate your own OREF

like set ref=##class(%Persistent).%Open($lb("9","Sample.Company"))

It's not really comfortable
 

it is possible. but an OREF is always a LOCAL reference !
see this example
 

SAM>kill
SAM>set a=##class(Sample.Person).%OpenId(2)
SAM>set b=##class(Sample.Person).%OpenId(12)
SAM>set c=##class(Sample.Person).%OpenId(111)
 
SAM>set x="3@Sample.Person"   ;what we look for
SAM>set o=""                  ;this will be our OREF  
SAM>zw
a=<OBJECT REFERENCE>[4@Sample.Person]
b=<OBJECT REFERENCE>[3@Sample.Person]
c=<OBJECT REFERENCE>[2@Sample.Employee]
o=""
x="3@Sample.Person"
SAM>;; now we convert our String x to OREF o
SAM>for  set o=$zobjnext(o) quit:(o="")||($p(o,"?")=x)
 
SAM>zw   ;; we did it
a=<OBJECT REFERENCE>[4@Sample.Person]
b=<OBJECT REFERENCE>[3@Sample.Person]
c=<OBJECT REFERENCE>[2@Sample.Employee]
o=<OBJECT REFERENCE>[3@Sample.Person]
x="3@Sample.Person"
SAM>

The key-oneliner:
for  set o=$zobjnext(o) quit:(o="")||($p(o,"?")=x)

MUCH more simple and shorter
 

kill
set a=##class(Sample.Person).%OpenId(2)
set b=##class(Sample.Person).%OpenId(12)
set c=##class(Sample.Person).%OpenId(111)

set obj=$zobjref("2@Sample.Person")

;; BINGO

zw
 
a=<OBJECT REFERENCE>[1@Sample.Person]
b=<OBJECT REFERENCE>[2@Sample.Person]
c=<OBJECT REFERENCE>[3@Sample.Employee]
obj=<OBJECT REFERENCE>[2@Sample.Person]

Now, why isn't $ZOBJREF() in the documentation?

What's the use case for this function?

Here's some (autotranslated) info about thesefunctions.

Also $zobjref accepts only integers, so you can pass just the part before @:

set a={}
set b={}
set obj1=$zobjref(1)
set obj2=$zobjref("1@Sample.Person")
zw

Results in:

a=<OBJECT REFERENCE>[1@%Library.DynamicObject]
b=<OBJECT REFERENCE>[2@%Library.DynamicObject]
obj1=<OBJECT REFERENCE>[1@%Library.DynamicObject]
obj2=<OBJECT REFERENCE>[1@%Library.DynamicObject]

There's also no guarantee that the object would be the same i.e.:

set a={"a":1}
set b={"b":1}
set aoref = ""_ a
kill a
set c={"c":1}
set obja=$zobjref(aoref)
zw obja
> obja={"c":1}  ; <DYNAMIC OBJECT>

What's the use case for this function?

ISC's Interoperability business rule editor has some quirks; it does not allow the passing of variables by reference to custom methods and that will cause objects to be passed as the OREF string in some cases. I was wondering if there was a way to work around that by obtaining another reference to the object by its OREF string, since that's what i ended up with.

I haven't tried this yet ... it may not work for the specific scenario I encountered. But this discussion has certainly helped me understand how things work under the covers a bit better.

It is dating back to the very early days of Caché. Even before my time @ ISC
(my guess >25 years)  There was a lot of $Z* stuff e.g. $ZU(..)  
That was not meant to be used for applications.
Just for internal use in system utilities. With no public Docs.
Some became public over time, mostly renamed,  and were documented.
I just found it by examing some related system functions.