In this scenario, a script fails to release its hold on a referenced item in the manner that one would expect, making the referenced item stay persistent and undeletable as long as the script runs, even if one carefully codes to have it properly released. It may be best described by an example:
First, a basic notification script:
ScriptName ZZHelloScripted extends ObjectreferenceEVENT OnCellAttach() Debug.MessageBox("Hello!")endEVENTThe point of this script is, that as long as the object it is attached to is in fact not yet deleted, the script notifies of this fact whenever the object's cell is attached, regardless of whether the item is enabled or not. It is very useful for testing deletion success. Let it be attached to some activator item (ZZTestItem2 in this example).
Then a second script, which is used to (1) place the previous item into the game world, specifically as a scripted version (which would make any properties and functions in the first script available to the second script, if there were any), and (2) then seemingly delete it.
ScriptName ZZTestScript extends ObjectreferenceActivator property ZZTestItem2 autoEVENT OnActivate(ObjectReference Dummy) ZZHelloScripted ItemRef = PlaceAtme(ZZTestItem2,1,False,True) as ZZHelloScripted ItemRef.Delete() ItemRef = None Utility.Wait(300.0)endEVENTOne would assume, that the second script properly deletes the referenced item as soon as it is placed, and since the referencing variable is properly set to None, the item should be fully released and not hang around once the beginning of the script is run. However, During the 5 minutes that the script continues to run, the item in fact remains, as can be tested by repeatedly having its cell attached.
The reason is, that when the second script is compiled, the lower "assembly level" output looks like this: (Decompiled with PapyrusAssembler)
.localTable .local ::temp0 form .local ::temp1 Objectreference .local ::temp2 zzhelloscripted .local ::NoneVar None .local ItemRef zzhelloscripted .endLocalTable .code Cast ::temp0 ::ZZTestItem2_var ;@line 6 CallMethod PlaceAtme self ::temp1 ::temp0 1 False True ;@line 6 Cast ::temp2 ::temp1 ;@line 6 Assign ItemRef ::temp2 ;@line 6 CallMethod Delete ItemRef ::NoneVar ;@line 7 Cast ::temp2 None ;@line 8 Assign ItemRef ::temp2 ;@line 8 CallStatic utility Wait ::NoneVar 300.000000 ;@line 9 .endCodeThe temporary variable ::temp1 is used to first receive the object reference before it is cast into ::temp2 (the scripted type) and it never gets reset or reused but is left holding on to the reference for the duration, which makes it persistent and undeletable. Manually adding into the "assembly level" script at the proper location the following line would fix it:
Cast ::temp1 NoneNormally people don't run long iterations inside single events/functions (although I do, because I like the fact that variables internal to a function are released and not saved with the hosting object unless the script is running). When a function/event terminates, all run-time variables inside it are released, and dangling issues like this should not usually occur or have a major impact.
But it may be useful to note, that in a specific scenario like this one, scripts can behave in an unexpected fashion in terms of their impact on the persistence or deletability of referenced objects, due to unseen temporary variables created during compilation.