Re: One other related Q Re: basic Q: Only one way to make vars live outside of the scope of a function without globals?



Hi,

"Ken Fine" <kenfine@xxxxxxxxxxxxxxxx> wrote in message
news:d51qsr$rp8$1@xxxxxxxxxxxxxxxxxxxxxxxxxx
>I have one other related question: if I instantiate a bunch of objects --
> say, recordsets -- in the context of a sub or function, will the objects
> be
> exposed to the rest of the page? (It would be nice to have
> "OpenPageRecordsets" and "ClosePageRecordsets " so that the page logic
> would
> be succinct and clear.)
>
>
> "Ken Fine" <kenfine@xxxxxxxxxxxxxxxx> wrote in message
> news:d51m0g$o92$1@xxxxxxxxxxxxxxxxxxxxxxxxxx
>> Great answer, Joe, thank you so very much for your thoughtful reply.
>>
>> Could I ask one other favor of you? You mention a system/convention of
>> prefixing that describes the scope of the variable and other useful
>> attributes to know. Can you show a sample of this convention, or maybe
>> recommend a book that describes the convention that you use? I'm very
>> interested.
>>
>> I've been on a six-month tear of reading through the best comp sci/comp
>> engineering literature I can find, and it's pretty cool to see all of the
>> tips, tricks and philosophies I've digested translated into markedly
> better
>> code. Your system sounds like something worth internalizing.
>>
>> -KF
>>
>>
>> "Joe Earnest" <jearnest3-SPAM@xxxxxxxxxxxxx> wrote in message
>> news:uKp1D%23eTFHA.3344@xxxxxxxxxxxxxxxxxxxxxxx
>> > Hi,
>> >
>> > <kenfine@xxxxxxxxxxxxxxxx> wrote in message
>> > news:eGg2QRdTFHA.616@xxxxxxxxxxxxxxxxxxxxxxx
>> > > This is a basic question about the design and intent of functions in
>> > > programming languages like VBscript.
>> > >
>> > > I know how to write VBScript functions and to pass parameter
>> > > variables
>> in
>> > > and out of them.
>> > >
>> > > As I've become a smarter programmer, I'm inclined to translate the
> lousy
>> > > code that I wrote when I didn't know what was doing into more
>> granularized
>> > > and encapsulated functions and/or classes.
>> > >
>> > > I was revisiting some VBScript browser detection code that looked
>> > > something
>> > > like this:
>> > >
>> > > ' check something
>> > > ' set a variable based on result of check
>> > > ' check something else
>> > > ' set a different variable based on result of check
>> > > ' check something else
>> > > ' set a different variable based on result of check
>> > >
>> > > The code sets about a dozen different variables of interest. The code
>> was
>> > > not organized as a function. It's certainly easy enough to make it a
> sub
>> > > or
>> > > function and to call it, but the variables that are set internally in
>> the
>> > > function don't live outside of the scope of the function.
>> > >
>> > > I want someone to confirm that the "correct" way/only way to make
>> > > many
>> > > variables survive outside of the function is to return an object
>> > > (e.g.
>> an
>> > > array) of values upon the function's completion.
>> > >
>> > > The function could write global vars, but that isn't good practice.
>> > >
>> > > Am I correct in this, or is there another way that I'm missing?
>> > >
>> > > Thank you,
>> > > Ken Fine
>> >
>> > For my two cents worth ...
>> >
>> > You missed a thread a couple of weeks ago where Al Dunbar (one of the
> MVPs
>> > here) and I had a lengthy "discussion" over a slightly more complex
>> version
>> > of your question.
>> >
>> > Given the straightforward nature of your question, I believe that the
>> answer
>> > is clearly "no," and I believe that most VBS scripters would agree,
> though
>> > perhaps in different ways.
>> >
>> > An array return (in scripting, "object" usually refers to a COM object
>> > instance and a specific data subtype) is great for similar multiple
> items.
>> > But it is the most obscure return, since you don't have the benefit of
> the
>> > variable name to provide quick identification. And at times you may
> want
>> to
>> > return quite different values -- both strings and object instances, or
>> > different types of references -- from a single function.
>> >
>> > VBS (unlike JS and some other languages) maintains the ByRef/ByVal
>> argument
>> > distinction, and defaults to ByRef. ByRef arguments provide for
>> > returns
>> > directly to the calling script, without having to use global variables
> to
>> > achieve the return. Indeed, there is no functional difference between
> the
>> > transitory function-name return and a ByRef argument variable return.
>> ByRef
>> > arguments have been the traditional method in BASIC programming, since
>> early
>> > DOS days, to get multiple return items from a subprocedure.
>> >
>> > mainNumRtn= myFunction(useValue1, useValue2, rtnObjVar, rtnStrVar)
>> >
>> > WMI functions are replete with return arguments -- indeed the WMI
> registry
>> > access system only works that way.
>> >
>> > The "trick", if you will, in using ByRef argument returns is either to
>> > document the function or to use a scope-oriented and functional
>> > variable
>> > prefixing system (instead of a simple variable-type system, which may
> not
>> be
>> > too useful in a pure variant language such as VBS). I strongly prefer
>> real
>> > prefixing. I can tell by looking at the first character of the
>> > argument
>> > variable name that I assign whether it's passed ByVal or ByRef, and if
>> > ByRef, whether its preserved, destroyed, coerced to the data type and
>> range
>> > required by the function, requires precise assignment, or set and
>> returned.
>> > The VBS option to use ByRef arguments is very efficient. But to take
>> > advantage of it, you must be willing to coerce or destroy some argument
>> > values, as well as reset some for return. This requires comment or a
>> > meaningful prefixing system, both to preserve your sanity and for reuse
> of
>> > the function in future scripts.
>> >
>> > A ByRef return argument for a function can be analogized to a property
>> > return for a method function. If your writing classes, you should
>> consider
>> > associated property returns. Since most I now write my fundamental
>> > functions as WSC VBS, I again use global variables for multiple return
>> > values, though these are declared in the parent XML script as
>> > properties
>> and
>> > returned to the calling script as properties. As you note, it is
>> generally
>> > better not to mix scope and use global variables for multiple return
>> values,
>> > in straight script, since it makes it hard to reuse the functions that
> you
>> > write.
>> >
>> > Regards,
>> > Joe Earnest
>> >

The short answer is no. Like all other local variable assignments, object
instances go out of scope when the local procedure goes out of scope. For
this reason, common scripting objects (FSO, Shell, WshShell, etc.) are often
used "against the grain" of the general rule not to use global objects in
local procedures, and are instead declared at the outset and used throughout
the script. Again, if you ever decide to use WSC files as general "utility"
and "include" files, the WSC file can declare the common objects globally on
its instantiation and pass them to the calling script through properties,
avoiding the need for the calling script to declare and instantiate
additional common object instances. But again, to use your WSC file
throughout your script, at both global and local levels, *it* would be
declared as an object in the global code and that global variable would be
used, again "against the grain" of the general rule, in local procedures.

Most sources do not explain COM object scoping and duplication well. The
following is one of my standard "schpeals" based on my own experience, but
also on some terribly useful explanatory posts in the past by Michael Harris
(MVP), Alex Angelopoulos (MVP), Chris Barber and Alexander Mueller.

Regards,
Joe Earnest

-----
When a typical COM class object is "accessed" by the creation of an
"instance" of the object, a pointer to the IDispatch interface and a new
virtual "object" is created as an interface definition of parameters with
assigned memory. Memory is allocated in which the new object's members may
store data. For the typical COM class object, a new pointer and virtual
object are created for each instance of the underlying object accessed.

If the COM class object is a "singleton" object, however, only a single
instance will be created, which will be shared not only by all object
variable instances in the same script, but by all scripts or other processes
accessing the object. In the case of a singleton object, the initiation
process first checks to see if an instance of the underlying object has
already been instantiated and, if so, returns a pointer to the same initial
virtual object. Thus (per the MS documentation): "If an object has
registered itself as a single-instance object, only one instance of the
object is created, no matter how many times CreateObject is executed. With
a single-instance object, GetObject always returns the same instance when
called with the zero-length string syntax, and it causes an error if the
pathname argument is omitted."

When all object access references are fully terminated, VBS runs a cleanup
process that deletes the pointers and begins the process of eliminating the
interface and memory allocation. An object will be disconnected only after
all references to it have been released. Windows may retain certain
references, depending on the object type and how it was instantiated. It is
possible, for example, to lock an object, when employing multiple object
references. Care must be taken with techniques and object types that allow
the object instance to continue beyond its scope in the script or even
beyond the termination of the script.

A review of posts relating to concerns with continued object connections and
"memory leaks" seems to indicate a number of reasonably distinct situations,
including, among others: (1) failure to properly exit a With statement
block by progressing through the End With statement; (2) multiple or
duplicate object references, where object variables in higher levels of
scope are not released; and (3) recursive procedures that create multiple
copies of an object. The most pernicious "memory leaks" appear to involve
EXE or special DLL objects, that are essentially applications, and which,
once initiated, continue independently, despite being released from the
object connections to the script. With these types of objects, it is always
best to try to force them to shut down through internal means, usually a
Quit method, before terminating the object reference.

The VBS process releasing the object references is part of the cleanup
procedures involved anytime that an object reference goes out of scope. For
purposes of an object variable as a reference to an existing object
instance, the going-out-of-scope cleanup is initiated for the existing
object reference whenever: (1) the variable is reset to Nothing or to a
different object reference, or even to a subsequent instance of the same
object reference; (2) the variable is reset to Empty or to a non-object
subtype or value; (3) the script is terminated; (4) a procedure in which the
object instance has been assigned to a local variable is exited; (5) the
inherent CreateObject function is used directly for a transitory instance of
the object, instead of assigning it to a variable; or (6) the CreateObject
function is referenced by a With statement block, and the script progresses
through the End With statement.

Setting unused object variables to Nothing is the "preferred" cross-platform
coding practice, and it is useful to release system resources more quickly,
when the object instance will not otherwise promptly go out of scope, but it
ultimately accomplishes nothing more in VBS than does any other method of
going out of scope.

When passing object instances to multiple scripts and/or multiple hosts, the
object instance will go out of scope whenever the originating script or host
is closed.

The inherent IsObject function simply returns the result of a check for the
appropriate index code in the variable list. It does not tell you if the
variable references any currently instantiated COM class object. For
example, an object variable reset to Nothing will still be returned as an
object variable, as will a variable whose object instance connection has
been terminated or otherwise lost. The intrinsic TypeName function can be
used as a secondary test in these situations. If the variable has been set
to Nothing, Typename will return Nothing; if the variable is connected to an
object instance, TypeName returns the specific object's ProgId, or the
default property subtype, if the object has a default property; and if the
variable is no longer connected to an object instance, TypeName returns the
generic Object status.

The IsObject function should still be used as a primary test for a specific
object, since both the inherent VarType and TypeName functions may return
the data subtype of the object's default property, depending upon the
specific object tested.



.



Relevant Pages

  • Re: Name collisions in Monad
    ... We spent a lot of time working on the scoping rules in Monad. ... create a new scope when run, and variables _created_ in that new scope are ... script, call a function, or start a new instance of Windows Command ... $var is initially set to "init" in the function ...
    (microsoft.public.windows.server.scripting)
  • Re: Can com+ Hotfix Rollup Package 27 fix my memory problem with WSH. CreateObject/CreateScript?
    ... > these activities have effects that are felt outside of the scope of a script ... Of course in script, the object will be ... > Even the above definition makes no distinction between object variables ... a connection every time I read or write a key, ...
    (microsoft.public.scripting.wsh)
  • Re: new to scripting.. the below script stops after first run..
    ... I have exports from my unix servers that aren't compatible with MS for a straight import so I've fiddled with the data, and now I want to just run the same script many times and pass it a bunch of parameters.. ... Echo Changing scope options ... Netsh dhcp server %server% scope %netid% add iprange %iprangestart% %iprangeend% BOTH> NUL ...
    (microsoft.public.windows.server.scripting)
  • Re: [MSH] WMI Help
    ... access the variable in the global scope whether or not the script is ... dot-sourced into the global scope then $script:class is equivalent to ... >> defined so it will search the stack and find it in the parent scope and ...
    (microsoft.public.windows.server.scripting)
  • Re: Can you have a command line arg with a workbook?
    ... "Patrick Molloy" wrote: ... but I guess I would still need the multiple IF statements (or ... Case if that works in VBScript?) ... this script starts a new instance of Excel. ...
    (microsoft.public.excel.programming)