Search code examples
vbscriptasp-classic

What is the difference between Dim and Public?


A question about scope was raised today and it got me thinking.

I've always understood VBScript scope and how to declare Globally and Locally. It occurred to me though that I never use Public variables but tend to use Dim instead when declaring Globally.

As far as I understood it Dim is the same as Public, but if that's the case why have both of them? Is there a difference between the two and is it good practice to use one over the other?


Update:

This question is aimed purely at VBScript, not VBA and especially in the context of Classic ASP.


Solution

  • Access restrictions make sense in modular or object-orientated languages. As Basic started as a simple procedural language, the later addition of such features make strict rules for using Dim, Public, and Private difficult.

    Everything below is about VBScript (not VBA, not ASP, not VB.NET)

    Facts:

    1. In out of Sub/Function/Class code, Dim, Public, and Private are equivalent: All declarations apply to the global scope
    2. In Subs/Functions/Methods you can use Dim only. The declarations apply to the Func/Sub/Method-local scope
    3. In class definitions, Dim and Public declare variables that are accessible for out-of-classe code; Private creates variables that can be accessed from class-code only. Private methods are callable from class-code only, Public methods (default) can be called from 'outer space'.

    Ruleset I:

    1. Use Dim for top-level declarations, because Public/Private have no discernible effect
    2. Use Dim in Subs/Functions/Method, because you must
    3. Use Public or Private (but not Dim) for member variable declarations, because the access permissions are important
    4. Use Private for private methods, but don't bother with Public, because it's the default

    Sample code:

    Option Explicit
    
    Dim     gsDim  : gsDim  = "gsDim"
    Public  gsPub  : gsPub  = "gsPub"
    Private gsPriv : gsPriv = "gsPriv"
    
    Class cX
      Dim     m_sDim
      Public  m_sPub
      Private m_sPriv
      Private Sub Class_Initialize()
        m_sDim  = "m_sDim"
        m_sPub  = "m_sPub"
        m_sPriv = "m_sPriv"
      End Sub
      Function ToString()
        ' Public Whatever => syntax error
        ' Private Whatever => syntax error
        Dim Whatever ' => no problem to use Dim for local declaration
        ToString = ToStringPriv()
      End Function
      Private Function ToStringPriv()
        ToStringPriv = Join(Array(m_sDim, m_sPub, m_sPriv))
      End Function
    End Class
    
    Function main()
      ' Public Whatever => syntax error
      ' Private Whatever => syntax error
      Dim Whatever ' => no problem to use Dim for local declaration
      main = 0
      WScript.Echo "in func main():", Join(Array(gsDim, gsPub, gsPriv))
      Execute "WScript.Echo ""via Execute:"", Join(Array(gsDim, gsPub, gsPriv))"
      Dim oX : Set oX = New cX
      WScript.Echo "oX.ToString():", oX.ToString()
      Dim s
     On Error Resume Next
      s = oX.ToStringPriv()
      WScript.Echo Err.Description
      s = oX.m_sPriv
      WScript.Echo Err.Description
     On Error GoTo 0
    End Function
    
    WScript.Echo "top level code:", Join(Array(gsDim, gsPub, gsPriv))
    WScript.Quit main()
    

    output:

    cscript dimpubpriv.vbs
    top level code: gsDim gsPub gsPriv
    in func main(): gsDim gsPub gsPriv
    via Execute: gsDim gsPub gsPriv
    oX.ToString(): m_sDim m_sPub m_sPriv
    Object doesn't support this property or method
    Object doesn't support this property or method
    

    Update wrt Kul-Tigin's comment:

    Ruleset II (when writing code for a host that supports modules):

    1. Treat modules as classes, i.e. apply I.3 and I.4 to your top-level variable rsp. Sub/Function declarations (because now access rights matter/are enforced)

    Code:

    Option Explicit
    
    Public  gsPub   : gsPub = "gsPub"
    Private gsPriv  : gsPriv = "gsPriv"
    
    Class AContext
        Public CodeObject
    End Class
    
    With (New AContext)
        Set .CodeObject = Me
        WScript.Echo .CodeObject.gsPub
        WScript.Echo .CodeObject.gsPriv
    End With
    

    Evidence:

    cscript dimpubpriv.vbs
    gsPub
    ... Microsoft VBScript runtime error: Object doesn't support this property or method: 'CodeObject.gsPriv''