Page 1 of 3
⎕USING and Dfns
Posted: Mon Jul 20, 2020 2:00 pm
by paulmansour
Consider the following function:
Code: Select all
OpenExcelFile←{
⍝ ⍵ ←→ File Name
⍝ ← ←→ .NET ZipArchive
⎕USING←'System.IO.Compression,System.IO.Compression.FileSystem.dll'
ZipFile.OpenRead⊂⍵
}
It works. But only if there is not some object (a variable, function, or namespace) named ZipFile as a sibling of OpenExcelFile. (Leaving aside what ⎕PATH might do!).
I can covert to a trad function, and localize ZipFile in the header, and then it will work properly in all cases. (The trad function in more functional than the dfn!)
Two questions:
1. Is there any way to properly do this in a dfn? That is, is there a more explicit way to say I want to use a .NET class?
2. In trad function, it would seem a requirement to localize any top-level .NET name one accesses as otherwise the function only really works by accident as is the case with the dfn. Or am I missing something?
Re: ⎕USING and Dfns
Posted: Wed Jul 22, 2020 3:48 pm
by paulmansour
To answer my own question (#1), while it does not explicitly locate the .NET class, we can localize a non-existing variable in a dfn, achieving the same result of putting a name in the header of a trad function, by creating it and deleting it. Thus:
Code: Select all
OpenExcelFile←{
⍝ ⍵ ←→ File Name
⍝ ← ←→ .NET ZipArchive
ZipFile←0
_←⎕EX 'ZipFile'
⎕USING←'System.IO.Compression,System.IO.Compression.FileSystem.dll'
ZipFile.OpenRead⊂⍵
}
This also has the salutary effect of not leaving behind a reference to ZipFile in the workspace. Not sure if that is a performance hit or not.
Re: ⎕USING and Dfns
Posted: Wed Jul 22, 2020 4:23 pm
by paulmansour
Some rough testing indicates no meaningful performance hit for localization of the .NET class.
Re: ⎕USING and Dfns
Posted: Wed Jul 22, 2020 4:35 pm
by PGilbert
In case it might help this
post is explaining my understanding of ⎕USING. I am retaining this passage from John:
The interpreter optimizes multiple assignments to ⎕USING so that assemblies are loaded all at once when a reference might need them - thus the behaviour you are seeing - the assemblies are not loaded into the appdomain until you force a reference.
I have tried the code in your first post in a )CLEAR WS (v18) and it is working for me.
Re: ⎕USING and Dfns
Posted: Wed Jul 22, 2020 7:14 pm
by paulmansour
I have tried the code in your first post in a )CLEAR WS (v18) and it is working for me.
Yes, it works in a clear workspace. The point is that is does not work in a workspace with a variable, function, or namespace named "ZipFile". It specifically relies are there NOT being such an object.
Re: ⎕USING and Dfns
Posted: Wed Jul 22, 2020 7:53 pm
by PGilbert
Sorry Paul, you are correct, it does not work when 'ZipFile' is defined outside of the dfn and does not seems to be the correct behavior to me also.
I have tried many things and I can't make it work the way you presented it.
Re: ⎕USING and Dfns
Posted: Thu Jul 23, 2020 7:47 am
by Veli-Matti
Hi,
.NET is not my favourite thing, but just occurred to me that this trick
might work:
OpenExcelFile←{
ZipFile←#
⎕USING←'System.IO.Compression,System.IO.Compression.FileSystem.dll'
_←⎕EX'ZipFile'
ZipFile.OpenRead⊂⍵
}
-Veli-Matti
Re: ⎕USING and Dfns
Posted: Thu Jul 23, 2020 1:34 pm
by paulmansour
Hi Veli-Matti,
That does indeed work as I showed above when I (partly) answered my own question. In a dfn, simply assigning 0 (or anything) to a name and then expunging the name effectively localizes the name. A subsequent reference to that name will produce a value error even if the name exists globally.
Re: ⎕USING and Dfns
Posted: Mon Aug 03, 2020 6:47 am
by StefanoLanzavecchia
paulmansour wrote:To answer my own question (#1), while it does not explicitly locate the .NET class, we can localize a non-existing variable in a dfn, achieving the same result of putting a name in the header of a trad function, by creating it and deleting it. Thus:
I'd do the same. But I'd probably set ZipFile to []NS'' just to show my intention of later overriding it with another "namespace".
This said, let me warn you of something I discovered empirically: if you localise ZipFile in a trad-fn and work with multiple APL threads (&), sometimes the interpreter does not put the external names back in ZipFile when switching from thread to thread. The bug has been reported more than once but there does not seem to be a simple solution at the horizon. And I got a recommendation by JD himself to never localize directly a .NET namespace but to always encapsulate those in a traditional namespace.
In other words, I changed all my code to be:
Code: Select all
_NET←⎕NS''
_NET.⎕USING←,⊂''
counter←_NET.System.DateTime.UtcNow.ToBinary.ToString ⍬
and I only localize _NET.
This works flawlessly. Notice that you can set []USING to your taste. My taste is to always use full names which makes my invocations very verbose, but you don't need to.
I don't know if the issues can be replicated in d-fns but I wouldn't be surprised if that was the case.
Re: ⎕USING and Dfns
Posted: Mon Aug 03, 2020 2:05 pm
by norbertjurkiewicz84
StefanoLanzavecchia wrote:paulmansour wrote:To answer my own question (#1), while it does not explicitly locate the .NET class, we can localize a non-existing variable in a dfn, achieving the same result of putting a name in the header of a trad function, by creating it and deleting it. Thus:
I'd do the same. But I'd probably set ZipFile to []NS'' just to show my intention of later overriding it with another "namespace".
This said, let me warn you of something I discovered empirically: if you localise ZipFile in a trad-fn and work with multiple APL threads (&), sometimes the interpreter does not put the external names back in ZipFile when switching from thread to thread. The bug has been reported more than once but there does not seem to be a simple solution at the horizon. And I got a recommendation by JD himself to never localize directly a .NET namespace but to always encapsulate those in a traditional namespace.
In other words, I changed all my code to be:
Code: Select all
_NET←⎕NS''
_NET.⎕USING←,⊂''
counter←_NET.System.DateTime.UtcNow.ToBinary.ToString ⍬
and I only localize _NET.
This works flawlessly. Notice that you can set []USING to your taste. My taste is to always use full names which makes my invocations very verbose, but you don't need to.
I don't know if the issues can be replicated in d-fns but I wouldn't be surprised if that was the case.
Very interesting. By chance I started doing this a years ago. I create a #.DotNET namespace where I initialize 99% of the .NET code at application startup.