Results 1 to 12 of 12
  1. #1
    sgerber
    Guest

    Public vs. Private vs. My Sanity

    I'm having a lot of trouble understanding this public vs. private business in VBA. To see how certain functions worked, I put together the following macro:

    Sub MAIN()
    INIFile = Options.DefaultFilePath(wdUserTemplatesPath) + _
    "" + Application.ActiveDocument.Variables("inifile").Va lue

    With ActiveDocument
    .BuiltInDocumentProperties(wdPropertyTitle) = ActiveDocument.Variables("docname").Value
    .BuiltInDocumentProperties(wdPropertySubject) = ActiveDocument.Variables("title").Value
    .BuiltInDocumentProperties(wdPropertyAuthor) = _
    System.PrivateProfileString(FileName:=INIFile, Section:="Current Settings", Key:="Writer")
    .BuiltInDocumentProperties(wdPropertyKeywords) = ActiveDocument.Variables("series").Value + _
    " #" + ActiveDocument.Variables("ish").Value + " " + "Script"
    End With
    End Sub

    As you can see, it doesn't reference any other macros -- yet when I try to run it, I get the following error message:

    "Compile error. Ambiguous name detected: INIFile"

    Yes, I've defined the variable INIFile in other macros, but -- at least the last time I tried to run them -- those macros didn't produce the same error.

    I ran into a similar problem when trying to use arrays of the same name (e.g., "Array_List()") in different macros. The array-gathering procedures were in a separate module called GetArrays, and no macro ever called the same-named array twice. (I hope that makes some kind of sense.)

    Anybody know what the #$%&# is going on here?!?

  2. #2
    Super Moderator jscher2000's Avatar
    Join Date
    Feb 2001
    Location
    Silicon Valley, USA
    Posts
    23,112
    Thanks
    5
    Thanked 93 Times in 89 Posts

    Re: Public vs. Private vs. My Sanity

    Here's my understanding. For a normal code module, variables declared at the top of the module (before any Sub or Function) have the following scope:

    Public strVar1 As String
    'valid in any procedure or function in the project
    Private strVar2 As String
    'valid in any procedure or function in this module;
    ' but invisible outside this module
    Dim strVar3 As String
    'same as Private strVar3 As String

    So why doesn't this give a compile error?

    Option Explicit
    Public strVar1 As String

    Sub test1()
    MsgBox strVar1
    strVar1 = "test1" 'changes global var
    MsgBox strVar1
    End Sub

    Sub test2()
    Dim strVar1 As String
    MsgBox strVar1
    strVar1 = "test2" 'changes procedure var
    MsgBox strVar1
    End Sub

    Hmmm...just bad practice, not illegal syntax, I guess.

    I don't think that declaring a Sub as Public (or Private or Static) makes any difference. Any variables inside the sub still only have scope inside the Sub. Does your testing conflict with this?

    Form modules may behave differently; I generally don't try to declare module-level or project-level variables in the form code module.

    For more info on variable scope in VBA, see VB & VBA in a Nutshell, by Paul Lomax.

    Wait a second... you have a document variable named inifile - maybe that is what is confusing the compiler?

  3. #3
    Plutonium Lounger
    Join Date
    Dec 2000
    Location
    Sacramento, California, USA
    Posts
    16,775
    Thanks
    0
    Thanked 1 Time in 1 Post

    Re: Public vs. Private vs. My Sanity

    If your question is why the same variable name declared both as a global and inside a sub doesn't cause a compile error, the answer is scope. Any variable declared inside a routine takes precedence over a variable of the same name declared at a higher level. VB/VBA works from the most restrictive scope up. You could declare the same variable name as global/public in a standard module, as private in another module, as local in a routine and as public or private in a class module without the compiler complaining about it, since the scope is different in each.

    If you declare variables public in form modules, which are actually class modules, you're declaring a public property of the form and the scope is limited to the time that form is open. If you try to use those variables without the form being open, you'll get a compile error. If you do use them from either inside or outside the form, you'll be getting or setting form properties with them.

    This
    <hr>INIFile = Options.DefaultFilePath(wdUserTemplatesPath) + _
    "" + Application.ActiveDocument.Variables("inifile").Va lue<hr>
    looks a lot like a circular reference to me, so it may be what is causing the compiler to spit up.
    Charlotte

  4. #4
    Platinum Lounger
    Join Date
    Feb 2001
    Location
    Yilgarn region of Toronto, Ontario
    Posts
    5,453
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Coding Standards

    > I'm having a lot of trouble understanding this public vs. private business in VBA.


    Good. So am I.


    I'm still working out what to do where, but for now I have settled into some basic habits that SEEM to keep me out of trouble (but wait until 5 seconds after I click the POST button ....)



    In any Word97/VBA application template I have a set of modules. One of these modules is especially unique to the application. This module holds all the user macros (which I choose to preface with "cmd_") and as well holds all the public string constants that are needed throughout the application. For example, if I have an application named "Under", I'll define "Public Const strcApplication = "Under"" in this module.


    I try to write each procedure as a function rather than a sub, and to provide all the required data via procedure arguments rather than by variables global to that procedure. It follows that I have little need for variables outside the scope? domain? of any procedure. Whatever the procedure needs is mentioned in its argument/parameter list, and the procedure either fills an array or listbox passed as an arguemnt, or returns a value (as a Function will).


    My ONLY use of a Private constant seems to be when I need a separate section of my INI file for different modules of an application; in this case each module will have a "Private Const strcModule as String = "MyModule"".


    Local/transient variables employed within a procedure are Dim-ensioned within that procedure. Hence I make use of repeated identical Dim statements in preference to having Global variable Dim-ensioned elsewhere. Global variables ALWAYS get me into trouble down the road.


    If it's any help to you I'll go examine a few application templates for exceptions to any of the guidelines I've mentioned above and we can examine the entrails and see WHY I chose the unorthodox method.



    In a nutshell - the more localized data is, the less trouble it can cause to other code. And passing data as procedure PARAMETERS ensures that we have declared the procedure interface in one place and one place only.

  5. #5
    Plutonium Lounger
    Join Date
    Dec 2000
    Location
    Sacramento, California, USA
    Posts
    16,775
    Thanks
    0
    Thanked 1 Time in 1 Post

    Re: Coding Standards

    Chris,

    just one comment about your "unorthodox method" of naming your routines as "cmd_whatever". In most of the naming conventions "cmd" is the prefix for naming a command button, so naming a routine starting with cmd is visually confusing because they all look like code for a command button at first glance. Nothing else in your stuff looks particularly unorthodox to me. What you're describing is generally referred to as "loosely coupled" code, and is encouraged by most, if not all, of the current gurus on VB/VBA.
    Charlotte

  6. #6
    Platinum Lounger
    Join Date
    Feb 2001
    Location
    Yilgarn region of Toronto, Ontario
    Posts
    5,453
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Re: Coding Standards

    > "cmd" is the prefix for
    naming a command button,


    Thanks. I'll change. I can change, you know (grin!)


    What would you (all) recommend then as a suitable prefix for a user macro (in the Word97/VBA sense)?

  7. #7
    Gold Lounger
    Join Date
    Feb 2001
    Location
    Dublin, Ireland, Republic of
    Posts
    2,697
    Thanks
    1
    Thanked 0 Times in 0 Posts

    Re: Public vs. Private vs. My Sanity

    You might like to read the following article at Microsoft's Knowledge Base. <A target="_blank" HREF=http://support.microsoft.com/support/kb/articles/Q141/6/93.asp?LN=EN-GB&SD=gn&FR=0>Q141693</A>

    Andrew

  8. #8
    Plutonium Lounger
    Join Date
    Dec 2000
    Location
    Sacramento, California, USA
    Posts
    16,775
    Thanks
    0
    Thanked 1 Time in 1 Post

    Re: Coding Standards

    Don't look at me, I refuse to put tags on code routines. However, I know programmers who customarily use udf (for user-defined function--yes, even for subs) to distinguish their custom routines from built-in stuff.
    Charlotte

  9. #9
    Platinum Lounger
    Join Date
    Dec 2000
    Location
    Queanbeyan, New South Wales, Australia
    Posts
    3,730
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Re: Coding Standards

    If I did put a naming standard on routines, I'd only be doing it on private routines.

    If there's something that a user might see, I'd keep away anything that might make it harder to understand. If I had a worksheet function, a user would find it much easer to remember "DoMyFunction" rather than "udfDoMyFunction".

    Just to be more controversial, I'd even be steering towards parameter names in a public function not having a prefix (I don't actually do this). It might be a little more work for me to remember as a coder, but easier for the coder when the list of parameters pops up when I'm coding a call to that function. The pop-up list does show the data type of the arguments.
    Subway Belconnen- home of the Signboard to make you smile. Get (almost) daily updates- follow SubwayBelconnen on Twitter.

  10. #10
    Plutonium Lounger
    Join Date
    Dec 2000
    Location
    Sacramento, California, USA
    Posts
    16,775
    Thanks
    0
    Thanked 1 Time in 1 Post

    Re: Coding Standards

    <hr>Just to be more controversial, I'd even be steering towards parameter names in a public function not having a prefix (I don't actually do this). It might be a little more work for me to remember as a coder, but easier for the coder when the list of parameters pops up when I'm coding a call to that function. The pop-up list does show the data type of the arguments.<hr>
    I agree. I waffle back and forth on this too. The data type is specified in the intellisense and the prefix makes the argument name ugly. However, when I'm actually reading the code where I've used named arguments, it is easier to see what I should have passed if there are prefixes on the parameter names.
    Charlotte

  11. #11
    Platinum Lounger
    Join Date
    Feb 2001
    Location
    Yilgarn region of Toronto, Ontario
    Posts
    5,453
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Re: Coding Standards

    >I'd keep away anything that might make it harder to understand.

    This makes sense.

    I started putting cmd_ as a prefix when I had everything jumbled together. Since the age of enlightenment arrived - when I learned about Toolbar menus and reorganized my life - all my user macros (SUB procedures with no arguments) are lumped together in a single module, so that it's easy for the programmer to see what is a part of the user interface.


    OK. Out go the cmd_ prefaces and the short-lived udf prefaces.


    >parameter names in a public function not having a prefix

    Did you mean "Prefixes for parameter names in a public function not having a prefix"?

    I use the bln/int/lng/str prefixes on all data/function identifiers.

    When I'm making use of a public function, the prompt pops up suggesting I use an argument like "strAr", which reminds me (my convention) that it is expecting a STRing ARray. I am assuming that this is the Intellisense that to which Charlotte referred.

  12. #12
    sgerber
    Guest

    Re: Public vs. Private vs. My Sanity

    >> This

    --------------------------------------------------------------------------------
    INIFile = Options.DefaultFilePath(wdUserTemplatesPath) + _
    "" + Application.ActiveDocument.Variables("inifile").Va lue
    --------------------------------------------------------------------------------

    looks a lot like a circular reference to me, so it may be what is causing the compiler to spit up. <<

    Charlotte,

    Thanks for the explanation of the declarations hierarchy.

    I don't think there's a circularity problem here, though. I'm just asking VBA to read the content of a document variable called "inifile" and use that string as the value of INIFile. (It does pick up the correct path and file name, by the way.)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •