"Namespace" reserved in VBA?

riktek

Member
Local time
Today, 08:43
Joined
Dec 15, 2023
Messages
102
"Namespace" is reserved in VB.NET but is not documented as such in VBA, as far as I can tell.

VBA bucks a bit when I attempt a "Public Property Get Namespace()" but seems to take the bit after compiling, saving, and cycling the app a few times.

Lest I court disaster and before I go too far down the road with this, however, I thought I'd check here for thoughts about such usage. Thanks in advance.
 
I don't see it in the list of reserved words I looked at. Are you sure it wasn't just some sort of name conflict? Could it be the same name as some other property that you already have a reference to? Just thinking out loud.
 
Don't risk using that name. Change it now.
 
There will be no problem. NameSpace is a keyword in VB but has no meaning in VBA.
If there was a problem then VBA would have to worry about a lot of other VB Keywords that do not have any meaning in VBA.

Simple example. VBA has Implements and not Inherits as keywords.

implements.PNG


So I can use Inherit without problem since there is no meaning in VBA. I cannot use implements since VBA does have this as a keyword. It will not compile.

VBA bucks a bit when I attempt a "Public Property Get Namespace()" but seems to take the bit after compiling, saving, and cycling the app a few times.
As @theDBguy suggested, this was unrelated. Code does not "kinda sort of compile".

The VBA list of Reserved words is more inclusive than just Keywords. It includes both Keywords and other words that could conflict with objects and be problematic if SQL. Not all are keywords. Keywords are part of the language and will not compile if used as a property, method, or variable name. You cannot name something For, next, loop, double, etc.

Pretty sure everything on that VB.net list of keywords would not compile if you name a variable using a keyword.
There are lots of access Reserved words that will compile and work without problem as variable, class method, or properties. I would not name a field, table, or control though.

"Reserved words" are words and symbols that have a specific meaning to Microsoft Access. If you use a reserved word or symbol to name a field in a desktop database or web app table, Access warns you that the word is reserved and that you might encounter errors when referring to the field.
You might also encounter errors if you use a reserved word to name a control, an object, or a variable."

So either it is going to compile or not. Since it compiled there is no problem.
Further, since it is a property of a class it is fully protected. For example I routinely have Custom classes in vba with properties like
Field, Recordset, Table, Name, Column, Row
and methods like
Requery, Sort, OrderBy
If it compiles (not a keyword) they are protected. It is not going to "sort of" conflict.


Don't risk using that name. Change it now
Just curious if this is based on something factual or just being extra cautious?
 
My thought is whether riktek has added a library reference for which the word "namespace" is either a class, property, or method. In my ancestry database, which involves Excel and Word, when I do an "Object Browser" search for NameSpace, I get partial-word and complete-word hits.

For example, in the Excel library, class XMLSchema has a property called "Namespace" while Outlook's library has a call to LookupNamespace, GetNamespace, and AddNamespace. It also has a class called Namespace, which I presume is what you manipulate with the Lookup..., Add... and Get... calls. So the odd behavior might be some kind of reaction to something unexpectedly overlapping with a reference library. Particularly if there is a chance that Intellisense could be involved.

@riktek - do you have the Excel or Outlook libraries checked in the VBA >> Tools >> References list? Or some other place? If you have VBA modules anywhere, even in a form's class module, open the VBA window. (e.g. with Alt/F11). From the icon tool bar, find Object Browser. If in doubt, just move your mouse cursor over each icon long enough for it to pop up the tool tip help. When you open Object Browser, there are two text boxes. The top one selects libraries. You want the option "<All Libraries>". The second text box is blank. Type in "namespace" (without the quotes) and then click the binoculars (search) icon. You will see if you have a Namespace property, method, or class in your project.
 
I don't see it in the list of reserved words I looked at. Are you sure it wasn't just some sort of name conflict? Could it be the same name as some other property that you already have a reference to? Just thinking out loud.
Thanks, no, I didn't see it on the VBA list of reserved words, either, although it's definitely on the VB.NET list.

There isn't an express naming conflict in the app. The property is the first use of "Namespace" in the app, ever. Also, the project does compile, after all, and this ordinarily surfaces ambiguous names, in my experience.

I suppose the question, or one of the questions, is whether there is, or might be, an implicit naming conflict, i.e., with the underlying Access C++ code. I stumbled across a few undocumented keywords last week, actually, which dialed up my sensitivity a bit. STDIN, STDOUT, and STDERR, in case you're wondering. I should probably do a separate post about those.

By "bucking," I mean that after writing the property and its backing module-level string variable:
  • Closing without compiling loops lengthily, requires Task Manager to close, then opens with the project irretrievably corrupted.
  • Closing after compiling and saving similarly loops but on reopening the project is intact.
  • Subsequent opens and closes go without a hitch.
It isn't clear, actually, whether I have a problem or may be courting one; that's actually the question. Perhaps just getting through compiling, saves, and cycling the app tells us things have settled down and that there isn't one. The behavior before getting to that point is unusual and a bit unnerving, however, and why I am proceeding with caution.

It doesn't sound as if there is a known problem using this name. Then, I suppose, the next question is whether any reason exists to think its usage might be risky. If not that we know of, then how might one exercise judgment in proceeding.

Again, thanks for the thoughts.

EDIT: This post didn't timely occur by reason of connectivity issues but was written immediately after @theDBguy 's initial response and before all others.
 
So either it is going to compile or not. Since it compiled there is no problem.
Pete, this was my initial take as well and thanks for confirming.

As noted in my prior response, which was written before yours but delayed in posting, the project does in fact compile and, after a bit of churn on closing, things settle down.

Further, since it is a property of a class it is fully protected.
Actually, it is a property of a standard module. I do this because this particular standard module defines application properties, including several object properties. As such, it should be a singleton; I don't want or need more than one instance, so doing this in a standard module prevents this conclusively. Also, being a standard module, it loads in its entirety on first reference (which occurs on startup), so I don't need to concern myself with predeclaration or instantiation. The properties self-heal (via static local or private module-level variables), so it's quite robust. Application events are another matter, however, and belong in a class so they can be sunk via class instances assigned to remote variables declared WithEvents.

@riktek - do you have the Excel or Outlook libraries checked in the VBA >> Tools >> References list? Or some other place?
No, none of these references exist in the project in question. I also double-checked by doing a search in the object browser and nothing turned up.

I should hasten to add, as noted in my prior post, that I don't actually know whether this usage poses or courts a difficulty; that's actually the question. @MajP thinks not, for important and valid reasons. This said, usage in other referenced libraries is important, as I learned recently with respect to STDIN, STDOUT, and STDERR. But, as noted, this isn't the case here.

Really, having ruled out express name conflicts, I suppose the question is whether any risk exists of an implicit naming conflict, i.e., with the underlying Access C++ code. @MajP seems to think not and I'm inclined to agree.
 
Really, having ruled out express name conflicts, I suppose the question is whether any risk exists of an implicit naming conflict, i.e., with the underlying Access C++ code. @MajP seems to think not and I'm inclined to agree.

By the time MSACCESS.EXE is running, any internal symbol-table variables are isolated by the very nature of creating an executable image. It has been a while since I built images, but if I recall correctly, you actually have to ASK to include an internal symbol table as part of an image. You CAN, but it isn't default behavior.

Access would not have lasted on the market for even a year with exposed internal symbols just waiting for the unsuspecting to trip over. The whole point of a DLL-style library is that you DO NOT have exposed variables. Instead, you have the equivalent of PropertyLet, PropertySet, or PropertyGet entry points. You have a few well-defined public entry points for SUB and FUNCTION code. But you have no way to DIRECTLY interact with the innards of the library. That pretty much isolates a LOT of stuff from folks reaching in and muddling. In a sense you would have to consider Access itself as a self-protected class object. IN A SENSE, for your purists...

For that reason, I concur with MajP that you don't have internal symbols exposed to the point of causing conflicts with code in your project.
 
@riktek,
You may want to look at the link discussed in this thread.

Although VBA does not have Shared methods like VB.net (Static like C), this shows how to fake it with using Predeclared. This makes it seem as if you can use the methods of the Class without instantiating. Basically it creates a global instance of the the class. This was completely new to me. The manual method is pretty simple but you can do this using the provided code.

Now you can have the benefits of a class module over your standard module, but not have to create an instance to use it.
 
[OT]
Note:
There is a simple way (video) to set VB_PredeclaredId = True without using an additional function or editing the exported text file:
  1. Write Attribute VB_PredeclaredId = True at the beginning of the codemodule in the VBA editor. It will be marked as an error. But that doesn't matter.
  2. Save the codemodule
  3. Export as text file (with SaveAsText or with shortcut menu in VBE)
  4. Reimport the file - the file does not have to be edited externally.
 
Last edited:
Access would not have lasted on the market for even a year with exposed internal symbols just waiting for the unsuspecting to trip over.
It's good to know that the compilation process provides a firewall of sorts in this regard. That probably rules out most of the risk scenarios I could envision and leaves me far more confident that a "Namespace" property or function won't court disaster.

This said, I have discovered that Access does have some undocumented hooks invisible in the object browser, and I've exploited some of these with great success. So, we can't say with certainty that compilation has eliminated every phantom API that might exist.
 
@MajP , you're quite helpful, and thoughtful, to raise these points. It turns out I'm deeply familiar with predeclaration, not to mention other dark arts of attribute manipulation, and have implemented it on a number of occasions. It's nifty as far as it goes but has its limitations.

Most narrowly, a predeclared class is instanced on first use, as is a standard module. A predeclared class nevertheless can be instanced further any number of times. Not that one would, deliberately, but still. A standard module simply cannot be instanced.

More practically, a standard module is simpler to implement in a library. As I noted, I don't need to fuss with predeclaration or instantiation if I use a standard module instead of a class module. More to the point, predeclared class modules don't travel well. Their attributes often revert to their defaults in the ordinary course of export and import, requiring time and special attention to restore or verify what turns out to be a precarious configuration. They do work better in the context of a library ACCDB, from which they are less likely to undergo periodic import and export. The appeal of a library ACCDB is that it only need be referenced but practically, these are cumbersome to maintain in a kaizen development environment.

Beyond these considerations, class modules, in my view, offer no distinct advantages over a standard module for the particular purpose of encapsulating application properties.

I would hasten to distinguish application settings and events. Application settings are, in my view, best kept in a back end table to which a global form is bound. Custom application events are, in my view, best kept in a class module instances of which can be assigned to variables declared WithEvents in modules where those events must be sunk.
 
particular purpose of encapsulating application properties.
Interesting. I did not know, nor did it even occur to me that you could use properties in a standard module. In all my time in VBA, I do not think I seen an example of someone doing this. In my mind properties always were part of an object. So learn something new everyday. So even when I really did not need multiple instances I always made a class to do this.
So except for events it basically gives the same functionality of a Shared method/class. For those who want a global variable that is a much better approach since the user can only come through the assessors.
 
So except for events it basically gives the same functionality of a Shared method/class. For those who want a global variable that is a much better approach since the user can only come through the assessors.
Re events, I haven't tried it yet but I expect one can sink events in a standard module via a module-level object variable declared WithEvents. What definitely can't be done is raise events to be sunk elsewhere. That requires a module instance being assigned to a remote WithEvents variable and, again, standard modules can't be instanced. This is why I would put custom application events in a dedicated class.

Re global variables, exactly, although I think the utility is greatest for global object variables (including native and bespoke collections) because they can self-heal. I use this module to return most of the Application object's object and collection properties, several counterparts in the DAO library, and some one-offs like the FileSystemObject. In another module, I have object functions that build on these, things like GetTableDefs(), GetQueryDefs(), GetFields(), etc. Otherwise, I have a separate module for constants, enumerations, and types where I keep a handful straight-up global string and numeric variables.

Also, the IntelliSense is pretty cool. I name the standard module "My", so I can do things like My.db, My.hWnd, My.References, My.VBE, My.fso, etc. I name the global form "frmMain", assign it to property Main, and derive Application from it: Set My.AccessApp = My.Main.Application. Whether I use an application property or object function depends partly on whether I subjectively want this My. notation when writing code.

Mike Wolfe uses a non-predeclared class as his application module. I obviously took another approach but what's most interesting to me is how he accesses it. He declares a public / global variable as Public App As New clsApp. I ordinarily avoid New in declaration statements because, although it isn't well-known or understood, Access not only instances the object on first reference, but also checks for an instance on every subsequent reference. The latter part adds processing overhead that ordinarily one should want to avoid. Here, though, using New in the declaration is all that's necessary to make the object variable self-healing. I jumped through other hoops but that still is cool.
 
Last edited:
...but I expect one can sink events in a standard module via a module-level object variable declared WithEvents
Standard modules cannot handle events.

Here, though, using New in the declaration is all that's necessary to make the object variable self-healing. I jumped through other hoops but that still is cool.
Here I would rather use a procedure to call it, so that you can pass initialization values and don't have to implement them in the class. (This makes it possible to use dependency injection etc.)

Code:
' Standard module:
Public App as New clsApp

'Class clsApp
Private Sub Class_Initialize()
    InitConfigData
End Sub

private Sub InitConfigData()
'   get data from table/ini-file/...
end Sub
vs
Code:
' Standard module:
private m_App as clsApp
Public property Get App() as clsApp
    If m_App Is Nothing
        set m_App = New clsApp
        InitConfigData m_App
    end If
    set App = m_App
End Property

private sub InitConfigData(byval AppRef as clsApp)
     'set app config from table/ini-file/...
End Sub
This makes clsApp easier to test because it is no longer dependent on a specific configuration variant.

On the topic of the "predeclared class":
I like the fact that you're not limited to the predeclared instance — you can still create additional instances using New.
 
Last edited:
Standard modules cannot handle events.
You're right. I just tried a WithEvents declaration and the VBE did not approve. Thanks for pointing that out.

Even were it possible, though, my initial instinct would be to handle custom application events in the global form's module, which is much better suited.

This makes clsApp easier to test because it is no longer dependent on a specific configuration variant.

Out of curiosity, why would your second InitConfigData() take its AppRef parameter ByVal and not ByRef?

Here I would rather use a procedure to call it, so that you can pass initialization values and don't have to implement them in the class. (This makes it possible to use dependency injection etc.)
I agree.

Mike's clsApp is static, though, not in need of configuration. For such a case, his approach is subtle and elegant, which I can't help but appreciate even if I did something else.

Your self-healing property is the approach I take, albeit without the hand-off to a configuration routine, which I hadn't thought of but like very much.

Depending on context, though, I may substitute a local static variable for the private module-level variable. So, the standard module My has properties AccessApp and Main backed by module-level variables mappAccess and mfrmMain, respectively. Then, I do:

Code:
Public Property Set Main(lfrmMain As Access.Form)

    Set mfrmMain = lfrmMain
    If Exists(mfrmMain) Then Set mappAccess = mfrmMain.Application
    
End Property    'PPS Main()

and, which might seem a bit of belt-and-suspenders:

Code:
Public Property Get AccessApp() As Access.Application

    If (Not Exists(mappAccess)) Then Set mappAccess = Main.Application
    Set AccessApp = mappAccess

End Property    'PPG AccessApp()

but note in the latter, I reference the property Main, not the variable mfrmMain because:

Code:
Public Property Get Main() As Access.Form

    If (Not Exists(mfrmMain)) Then LoadApp
    Set Main = mfrmMain
    
End Property    'PPG Main()

LoadApp() opens the global form frmMain, which assigns itself to My.Main, at the top. So, the properties mutually self-heal. Other properties are dependant, however, so might look like:

Code:
Public Property Get VBE() As VBIDE.VBE

    Static vbeThis As VBIDE.VBE
    
    If (Not (Exists(vbeThis))) Then Set vbeThis = AccessApp.VBE
    
    Set VBE = vbeThis

End Property    'PPG VBE()

No Property Set or module-level variable exists for this property, so it isn't exposed for writing even from within the module. At the same time, calls to this property will cascade self-heal itself, AccessApp, and Main. This approach also helps enforce project scope by default.

I like the fact that you're not limited to the predeclared instance — you can still create additional instances using New.
When one doesn't want such limitations, it's a perfect solution. When one does, however, a standard module can work quite well. This is a very narrow case, of handling application properties, where the latter is useful.

I would hasten to add, however, that this does not preclude the kind of bespoke application configuration you describe. Ultimately, as implemented, My is simply a self-healing cache for COM objects in the current Access application. It can be extended to application-specific settings but doesn't preclude a class, predeclared or not, when instancing or event handling is required.

I would, however, argue that application-specific configuration should, and even must, exist in a singleton module. Instancing implies distinct configurations, after all, which would seem antithetical to this purpose. For this, where a class is necessary, I still would not use a bespoke class per se, predeclared or not. Instead, I would use the global form's module. Forms in some respects are just class modules with a GUI, and global forms typically exist as singletons. Form modules also are predeclared, which isn't often discussed, but regardless, global forms ordinarily are configured to open with the app. Predeclaration is moot because the global form's module has been instanced on startup. Encapsulating application-specific code here also gives one powerful control over how and when an app runs, or doesn't.
 
Application settings are, in my view, best kept in a back end table to which a global form is bound.
No. That makes it difficult to replace the FE because you have to somehow save the user settings. Best to use a BE table with a UserID so each user has his own values. Application specific settings that cannot be changed by the user can be stored separately in either the FE or BE since they are under the control of the programmer.
 
Out of curiosity, why would your second InitConfigData() take its AppRef parameter ByVal and not ByRef?
Why should I use ByRef if I don't want to change the reference? ;)
 
Why should I use ByRef if I don't want to change the reference? ;)

Not that you should, of course, but the reason I generally would is efficiency, unless I had a specific reason to use ByVal.

For objects, ByRef passes the pointer itself, while ByVal passes a copy of the pointer (not, to be clear, another instance of the object).

ByRef allows one to change the reference but doesn't require it. It also avoids the overhead of creating the copy and then clearing it. Yes, setting a ByRef reference to Nothing anywhere clears it everywhere, but this is both good to know and quite handy. This might seem a trivial optimization but in a highly atomic library where a pointer might pass through several classes, or a half dozen object functions or properties on each of many iterations, it helps. Not only on execution, but also on the efficiency of DoEvents calls.

My idiosyncratic view is not so much to use ByRef only when I need passback, as to use ByVal only when I want to avoid it (or is required by the API for out-of-process stuff).

Practically, this means I tend to use ByRef for all object parameters and nearly all others, and ByVal only when I want to avoid overwriting something like a parked string or PK value. I also can't think of a single instance when I reset a ByRef object reference, other than for garbage collection. For garbage collection in an object framework, though, it's the only way to go.

But, YMMV. I'll be the first to admit this view largely can be attributed to a nitpicky style, or too much time spent programming classes.
 
No. That makes it difficult to replace the FE because you have to somehow save the user settings. Best to use a BE table with a UserID so each user has his own values. Application specific settings that cannot be changed by the user can be stored separately in either the FE or BE since they are under the control of the programmer.
That's a good point. I'm conflating user-specific settings and application-specific settings. I'd put both in the BE for just the reason you state, to permit FE versioning. I can't imagine many reasons at all to keep any configuration data in a FE.
 

Users who are viewing this thread

Back
Top Bottom