Ken
Sun May 01 11:35:15 CDT 2005
Thank you for your generous responses, Joe. This is excellent.
Regards,
Ken Fine
"Joe Earnest" <jearnest3-SPAM@earthlink.net> wrote in message
news:OFDlZllTFHA.3140@TK2MSFTNGP14.phx.gbl...
> Hi,
>
> "Ken Fine" <kenfine@u.washington.edu> wrote in message
> news:d51m0g$o92$1@gnus01.u.washington.edu...
> > 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@earthlink.net> wrote in message
> > news:uKp1D%23eTFHA.3344@TK2MSFTNGP12.phx.gbl...
> >> Hi,
> >>
> >> <kenfine@u.washington.edu> wrote in message
> >> news:eGg2QRdTFHA.616@TK2MSFTNGP12.phx.gbl...
> >> > 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
>
> First off, my apologies for the omitted phrases and bad grammer in the
last
> response. It had been a long day.
>
> Prefixing systems are the type of thing that can create flame posts --
> people seem to take them very personally. My system has developed through
> DOS to Windows and ASM to scripting. My current system, however, is
focused
> on VBS, and even underwent a bit of a change a couple of years ago, when I
> switched largely to WSCs from straightforward scripting. There are a
number
> of factors to consider in choosing a prefixing system that may make my
> approach unsuitable for you. Probably the two most significant ones are:
>
> 1) The peer group where you work or with whom you exchange or mutually
work
> on code, or a potential successor for a client, or even a publication, may
> expect or require a prefixing system that everyone can recognize quickly;
> and
>
> 2) If you are working in multiple platforms and languages, and
particularly
> if those multiple platforms or languages are involved in the same code or
> project, you may need to adapt your prefixing system to a
> least-common-denominator approach that addresses the requirements and
quirks
> of all the platforms and languages involved.
>
> Also, before I give you my prefixing system, you might want to take a look
> at Eric Lippert's blog on type prefixing in VBS. Eric Lippert wrote a
> substantial amount of the VBS code for MS.
>
>
http://blogs.msdn.com/ericlippert/archive/2003/09/12/52989.aspx
>
> A bit of history that may be useful when reading Eric's blog, or other
> people's comments (from Alex Angelopoulos [MVP]):
>
> "Suggested naming conventions abound, most variants of Hungarian Notation
> (HN), a standard for variable naming developed at Microsoft in the early
> 1980's for use in workgroup-based C coding. The real story is not this
> convention but the concepts researched by it's father, Charles Simonyi.
In
> graduate research at Xerox PARC he extensively investigated group-based
> coding. He focused heavily on how code can be improved by use of certain
> shared conventions. To this day one of the clearer benefits of any naming
> standard is ensuring that when you look at code you quickly can see what a
> variable represents and what a function does."
>
> Let me say at the ouset that I claim no "divine insight" in my prefixing
> system, or that it would work for anyone else. It is not even strictly
> logical, but has simply proven to be more useful to me than a strictly
> logical system. It will likely not be intuitively recognized by other
> scripters. It is optimized for VBS and even for WSC-hosted VBS, with a
> secondary focus on mark-up languages (HTML, XML, etc.), so its
> cross-platform and cross-language application is questionable.
>
> Regards,
> Joe Earnest
>
> -----
> Modified mark-up language "camel" casing is employed for all user-defined
> names; external objects, properties and methods; and constants. The
initial
> name segment is fully lowercased, while the initial character of
> non-delimited secondary name segments is capitalized. All inherent VBS
> keywords and function names fully lowercased. Entities and names created
> through XML and HTML methods are named as if they were created through VBS
> methods.
>
> All procedures are declared as functions, even if they provide no return
and
> are designed to be called only as statements. Unexposed functions are
> prefixed with an initial "fn" segment. Exposed methods and properties,
and
> their corresponding functions, are not prefixed, unless a conflict with an
> inherent VBS name requires the internal function to be prefixed.
Unexposed
> components (loosely, the WSC file equivalent of classes) are designated
with
> an initial "cp" segment, while exposed components are named to provide a
> recognizable call.
>
> All script is "Option Explicit". Variables are declared when and where
> required. The VBS "Const" statement is never used. The underscore
> character is not used in variable names, unless use is compelled by
context,
> but is, instead, reserved solely for line continuations.
>
> All variable names are prefixed, except for object variables that access
> unexposed components. This allows the variable name to be used as an
> exposed property.
>
> My peculiar variable prefixing is oriented toward identifying scope and
> usage, as well as identifying data subtype, when useful. Variables are
> given concise name segments to differentiate them and generally identify
> their content in context. Pluralized names are used for totals, as well
as
> for transitory variables that may change subtypes between arrays and
string
> lists. For example, in a hypothetical procedure, "viFile" could be a
local
> counter or iteration of files, "viFiles" could be a local reference to the
> total number of files, "vaFiles(...)" could be a local array of file
> objects, "vsFileName" would be a local file name string, and "vsFileNames"
> would be a local string list of file names that could be changed back and
> forth, to and from, an array, using the VBS "Split" and "Join" functions.
>
> Prefixing involves two characters: (1) the first indicates scope and
> argument usage, or is omitted for global variables; (2) the second
indicates
> type and usage, to the extent that I have found it useful.
>
> Variable Scope Prefix
>
> none e.g., sFile
> Globally defined.
>
> v e.g., vsFile
> Locally defined or ByVal argument. Both local definitions and ByVal
> argument variable values go out of scope when the procedure is exited.
All
> ByVal arguments are internally coerced to the procedure's required data
> subtype and/or range, but, because it is ByVal, the value passed is
> preserved. Note that, in VBS, object instances are always passed ByRef,
> even if there is a ByVal argument statement.
>
> r e.g., rsFile
> ByRef argument returned. The value passed is modified in the procedure
for
> return to the calling script. If an initial value is required, the data
> passed will be internally coerced to the required data subtype and/or
range.
>
> u e.g., usFile
> ByRef argument unchecked. Data for the argument must be passed as the
> anticipated subtype and/or range, to avoid an error in the procedure. The
> value passed is preserved.
>
> p e.g., psFile
> ByRef argument preserved. The data passed is coerced to the anticipated
> subtype and/or range without destruction, so that the value passed is
> preserved.
>
> c e.g., csFile
> ByRef argument coerced and destroyed. The data passed is coerced to the
> anticipated subtype and/or range, destroying the data passed.
>
> Variable Type and Usage Prefix
>
> The final variable prefix character indicates the variable's type and/or
> usage. All categories include an initial "Empty" data subtype, as well as
> any data subtype passed through a function's argument, or returned from a
> function, method or property, until the anticipated data type can be
> coerced. These categories have developed historically and
idiosyncratically
> over time, and have simply proved useful to me. They don't necessarily
make
> sense.
>
> a e.g., aFile, vaAmount
> Array. A variable that is declared and maintained solely as an array.
> Transitory string-list arrays may have an "s" prefix. Transitory
> string-lists that convert to arrays with mixed data types may have an "x"
> prefix. Note that this prefix does not articulate the data subtype(s) or
> any other aspects of its elements.
>
> f e.g., fErr, vfExists
> Boolean or numeric flag. A Boolean subtype, or a (long) integer numeric
> subtype with a value of "0" or "-1".
>
> i e.g., iRep, viItem, viItems, viInStrChr, viBit
> Integer or long integer. A (long) integer subtype used in a uniquely
> "integer" manner, as an instance, counter, pointer, address, element
number,
> position, bitwise, sequential or other numeric code, etc., or, with a
plural
> name, the total instances or the UBound of an array.
>
> n e.g., nHt, vnAmount
> A numeric subtype. Any other numeric data subtype or numeric usage.
>
> s e.g., sFile, vsName, vsFileList
> String. Any string data subtype or usage. May also include transitory
> string lists that are changed back and forth to or from arrays.
>
> o e.g., oFso, voShell, uoWshShell
> Object. An object instance data subtype or usage. Because VBS requires
> that object variables be passed ByRef, all object variables passed to a
> user-defined procedure should have a prefix indicating ByRef status.
> Scriptlet object variables that are exposed as properties in order to
allow
> access to unexposed components, are not prefixed, so that the variable
name
> may be used as an exposed property name.
>
> d e.g., dFileDate, vdToday
> Date. A date-time data subtype or usage.
>
> k e.g., kVersion, kSomeBitFlag
> Constant. Data of any subtype that is intended to be fixed and unchanged,
> once determined. Rarely used, but almost always global in scope, when
used.
> The VBS "Const" statement is not used, as such.
>
> x e.g., xUtility, vxArgCode, vxValueList
> Other, transitory or multi-type. A data subtype such as "Null" or
"Error",
> a transitory utility variable, a transitory string list that is converted
to
> or from a mixed data-type array, or an argument that may be validly
assigned
> different data subtypes.
>
>