Why isn't a value transferred from a function

In a view action script there is a line Set docReport = GetReport(note)

where docReport (Dimmed as NotesDocument) is supposed to get a value from the custom defined

Function GetReport (doc as NotesDocument) as NotesDocument

The last three lines of the function GetReport are:

Set docOld = < another custom function that works OK>

Set GetReport = docOld 

End Function

Everything works fine in the function GetReport, and in the Debugger I can see that both docOld and the function GetReport is getting the value of the correct document that the function should return.

However, when I immediatly thereafter inspect by the debugger the value of docReport that in the first statement above should have received the value from the successful GetReport function, docReport is still Nothing!

Any idea on what (not) happens here would be most welcome.

Subject: Why isn’t a value transferred from a function

Old feature/bug. I’ve seen exactly what you’re talking about since version 4.0. Here’s how to work around it. You must pass your function a database object. It’s the database where the returned document is found.

Function GetReport( db as NotesDatabase, doc as NotesDocument) as NotesDocument

When GetReport returns the NotesDocument, it must be found in db, and db must be an object in the calling script.

db = …some database containing docReport

set docReport = GetReport(db,note)

Strange huh?

Subject: It’s all about scope and context…

You probably create a database object in the getReport function, and then get the document object from that parent database object. Well, when your getReport function finishes running, it “cleans up” any objects created locally in the function, or “in the context” of the function. When an object is destroyed, all child objects are destroyed as well. Therefore when your document is returned from getReport, it is immediately destroyed because the parent database object is destroyed as it has left the scope of the function.

The way around this is to either pass the parent database object into the function as an additional parameter, or set the database to a global so that it is available within and out of the function.

Clear as mud? :wink:

Rocky Oliver
Sapphire Oak Technologies
EML: rock@sapphireoak.com
**If you drink a whole pot of coffee and then go to bed, do you dream in fast forward?


<<< Rocky is speaking at these upcoming events… >>>
IBM DeveloperWorks Live!
New Orleans, LA – April 9 - 12, 2003
http://www.ibm.com/events/developerworkslive


Subject: RE: It’s all about scope and context…

Thanks for the competent input from the both of you, Beau and Rocky.

I understand that objects/variable within the module of a function will be extinguished when the function completes, however it is most disturbing news to me that the resulting expression of a function anyhow won’t necessarily be conveyed back to the call of the function – in particular as the resulting value is a reference to an existing document.

My problem is that when I make the call to

 Function GetReport (doc as NotesDocument) as NotesDocument

in the statment

          Set docReport = GetReport(note)

I don’t know in which database the resulting docReport is stored.

Function GetReport identifies the dbTarget within itself, by a call to another function GetDb as NotesDatabase, which looks up a dbReplicaID from a set-up document and then finally

Set docOld = dbTarget.GetDocumentByUNID(doc.ReportID(0) )

Set GetReport = docOld 

End Function

(The point has been to simplify/standardize for reuse/maintenance and taking care of the handling of various other things that goes on besides this, otherwise the calling script could directly have stated

    Set docReport = dbTarget..GetDocumentByUNID(note.ReportID(0) ) 

which appearantly would have avoided the problem now encountered.)

So from what you guys are saying, I will have to complicate things a little more in the calling script by adding there first a call to the functon GetDb and then send the resulting db into the GetReport as an additional parameter?

Alternatively, I should establish a global variable for the dbTarget that can be sent as the additional parameter.

The functions GetReport and GetDb are parts of a script library, while the script calling GetReport could be anywhere (including in the same script library). Will it then be sufficiant to have that global db-variable declared in the Declarations part of the script library?

Subject: RE: It’s all about scope and context…

Alternatively, you could pass an argument to the function for it to receive the database into, as I did in this example:

Sub Click(Source As Button)

Dim maildb As NotesDatabase

getmail maildb

If maildb Is Nothing Then Print "maildb is nothing" Else Print {"} & maildb.Server & {", "} & maildb.FilePath & {"}

End Sub

Sub getmail(x As NotesDatabase)

Set x = New NotesDatabase("", "")

x.OpenMail

End Sub

Or, you could define a structure type containing a database and document and make that your return value.

Or, you could go the object-oriented route, have a document finder class that internally stores the database object and returns the document. That way the database doesn’t get freed until you’re done with the finder object.