Fooling around with the .Package class a week ago, I see a difference in
behavior between using loadPackage('myFile') and .Package~new('myFile')
that I don't understand. I wonder if this is intentional or not.
Say I have a very simple file: mypackage.cls. Having skimmed the docs some
time ago, I had the feeling that these 3 statements were all equivalent:
::requires 'mypackage.cls'
.Package~new('mypackage.cls')
packageObj~loadPackage('mypackage.cls')
And, since 4.0, I thought that in one single interpreter process, the
::requires 'mypackage.cls' would only load mypackage.cls once.
However, in a large number of iterations, I see that
.Package~new('mypackage.cls') will sometimes return a new .Package object
and reload the mypackage.cls file. Whereas
packageObj~loadPackage('mypackage.cls') always returns the same .Package
object and does not reload mypackage.cls
The code for a simple test showing this is below.
I don't understand why the behavior between the two is different. I
expected both to only load the mypackage.cls file once. But, in the
PackageManager class I see this code / comment:
WeakReference *requiresRef = (WeakReference *)loadedRequires->get(name);
if (requiresRef != OREF_NULL)
{
RoutineClass *resolved = (RoutineClass *)requiresRef->get();
if (resolved != OREF_NULL)
{
result = resolved;
return resolved;
}
// this was garbage collected, remove it from the table
loadedRequires->remove(name);
}
return OREF_NULL;
The "this was garbage collected" comment makes it seem like it might be
expected that the same .Package object might not always be returned. But,
then why don't both approaches do the same thing?
Here is a simple program that shows the 'mypackage.cls' is reloaded
sometimes:
/* mypackage.cls */
say 'mypackage.cls loaded'
exit
/* packageNew.rex */
obj1 = .Thread~new('thread 1')
obj2 = .Thread~new('thread 2')
obj1~work
obj2~work
::class 'Thread'
::method init
expose name
use arg name
::method work unguarded
expose name
reply 0
str = '1'
e = time('e')
stopTime = 5
do while .true
src = .Array~new(4)
src[1] = "use arg name"
src[2] = "p = .package~new('mypackage.cls')"
src[3] = "say name 'p identiy hash' p~identityHash"
src[4] = "return 0"
rtn = .Routine~new('myRoutine', src)
ret = rtn~call(name)
str += '1'
if str > 1000 then do
str = '1'
if time('e') > stopTime then leave
end
end
Run the above like this:
packageNew.rex > packNew.log
It runs for about 5 seconds. I see that typically the prolog is executed
about 35 times, when I expected it to be only executed once.
This is the same program, but the routine's source array is changed to use
loadPackage():
/* loadPackage.rex */
obj1 = .Thread~new('thread 1')
obj2 = .Thread~new('thread 2')
obj1~work
obj2~work
::class 'Thread'
::method init
expose name
use arg name
::method work unguarded
expose name
reply 0
str = '1'
e = time('e')
stopTime = 10
do while .true
src = .Array~new(5)
src[1] = "use arg name"
src[2] = "currentPackage = .context~package"
src[3] = "p = currentPackage~loadPackage('mypackage.cls')"
src[4] = "say name 'p identiy hash' p~identityHash"
src[5] = "return 0"
rtn = .Routine~new('myRoutine', src)
ret = rtn~call(name)
str += '1'
if str > 1000 then do
str = '1'
if time('e') > stopTime then leave
end
end
For loadPackage() I see that the docs say the file "will be located and
loaded as if it had been named on a ::REQUIRES directive. And "if a
package name has already been loaded by the package manager, the previously
loaded version will be used."
But, for new() it doesn't actually say that.
Well, after having written all that, I see that
.Package~new('mypackage.cls') is not documented as working at all. ;-(
Still it seems to work to a degree. Maybe the documentation needs to be
cleaned up a bit for ~new()?
--
Mark Miesfeld
------------------------------------------------------------------------------
This SF.net email is sponsored by Windows:
Build for Windows Store.
http://p.sf.net/sfu/windows-dev2dev
_______________________________________________
Oorexx-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/oorexx-devel