Problems caused by Spaces in Field and Control Names - ms-access

Obviously including spaces in table names, field names and control names is a bad idea (since it is used as a separator in practically all the imperative programming languages use commercially today*). You have to surround those controls and fields with [], etc. I'm trying to demonstrate another one of the problems with spaces to someone else.
I seem to recall that there is a situation that can arise where because a field name has a space in it (e.g., "Foo ID") and a control based on it is also called "Foo ID", that you can end accidentally referencing the underlying field instead of the control.
e.g., you update Foo ID from empty to "hello world" and then you need to check the value for null before the record is saved; something like "me.[Foo ID]" returns Null instead of "Hello World"
How can I duplicate this unexpected behaviour?
(* - Lisp, Prolog and and APL aren't imperative programming languages)

Since the control name can't have spaces in it when you reference it in code using the default controls property of the form (ie, Me.Foo_ID), the spaces are replaced with underscores. So in your example, Me.Foo_ID would refer to the control, but Me![Foo ID] would refer to the underlying field. (Even this statement appears incorrect on further consideration: Me![Foo ID] almost certainly refers to the control named "Foo ID".)
As David Fenton rightly points out, the control itself can be named with spaces. And it can be referenced in code with spaces when referenced as follows: Me.Controls("Foo ID") or Me![Foo ID] as those forms can properly handle spaces. But if you want to use the shorthand, you'll need to add the underscore: Me.Foo_ID.
In that case Me.Foo_ID would return "Hello World" before the record is saved (while the form is Dirty), but Me![Foo ID] would return Null.
EDIT: After some testing I have not been able to actually reproduce the odd behavior you are after (using several different combinations).
Thanks to David Fenton for setting me straight (please let me know if I'm still off somewhere).

Related

COBOL code to replace characters by html entities

I want to replace the characters '<' and '>' by < and > with COBOL. I was wondering about INSPECT statement, but it looks like this statement just can be used to translate one char by another. My intention is to replace all html characters by their html entities.
Can anyone figure out some way to do it? Maybe looping over the string and testing each char is the only way?
GnuCOBOL or IBM COBOL examples are welcome.
My best code is something like it: (http://ideone.com/MKiAc6)
IDENTIFICATION DIVISION.
PROGRAM-ID. HTMLSECURE.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
77 INPTXT PIC X(50).
77 OUTTXT PIC X(500).
77 I PIC 9(4) COMP VALUE 1.
77 P PIC 9(4) COMP VALUE 1.
PROCEDURE DIVISION.
MOVE 1 TO P
MOVE '<SCRIPT> TEST TEST </SCRIPT>' TO INPTXT
PERFORM VARYING I FROM 1 BY 1
UNTIL I EQUAL LENGTH OF INPTXT
EVALUATE INPTXT(I:1)
WHEN '<'
MOVE "<" TO OUTTXT(P:4)
ADD 4 TO P
WHEN '>'
MOVE ">" TO OUTTXT(P:4)
ADD 4 TO P
WHEN OTHER
MOVE INPTXT(I:1) TO OUTTXT(P:1)
ADD 1 TO P
END-EVALUATE
END-PERFORM
DISPLAY OUTTXT
STOP RUN
.
GnuCOBOL (yes, another name branding change) has an intrinsic function extension, FUNCTION SUBSTITUTE.
move function substitute(inptxt, ">", ">", "<", "<") to where-ever-including-inptxt
Takes a subject string, and pairs of patterns and replacements. (This is not regex patterns, straight up text matching). See http://opencobol.add1tocobol.com/gnucobol/#function-substitute for some more details. The patterns and replacements can all be different lengths.
As intrinsic functions return anonymous COBOL fields, the result of the function can be used to overwrite the subject field, without worry of sliding overlap or other "change while reading" problems.
COBOL is a language of fixed-length fields. So no, INSPECT is not going to be able to do what you want.
If you need this for an IBM Mainframe, your SORT product (assuming sufficiently up-to-date) can do this using FINDREP.
If you look at the XML processing possibilities in Enterprise COBOL, you will see that they do exactly what you want (I'd guess). GnuCOBOL can also readily interface with lots of other things. If you are writing GnuCOBOL for running on a non-Mainframe, I'd suggest you ask on the GnuCOBOL part of SourceForge.
Otherwise, yes, it would come down to looping through the data. Once you clarify what you want a bit more, you may get examples of that if you still need them.

Three rows of almost the same code behave differently

I have three dropdown boxes on a Main_Form. I will add the chosen content into three fields on the form, Form_Applications.
These three lines are added :
Form_Applications.Classification = Form_Main_Form.Combo43.Value
Form_Applications.Countryname_Cluster = Form_Main_Form.Combo56.Value
Form_Applications.Application = Form_Main_Form.Combo64.Value
The first two work perfectly but the last one gives error code 438!
I can enter in the immediate window :
Form_Applications.Classification = "what ever"
Form_Applications.Countryname_Cluster = "what ever"
but not for the third line. Then, after enter, the Object doesn't support this property or method error appears.
I didn't expect this error as I do exactly the same as in the first two lines.
Can you please help or do you need more info ?
In VBA Application is a special word and should not be used to address fields.
FormName.Application will return an object that points to the application instance that is running that form as opposed to an object within that form.
From the Application object you can do all sorts of other things such as executing external programs and other application level stuff like saving files/
Rename your Application field to something else, perhaps ApplicationCombo and change your line of code to match the new name. After doing this the code should execute as you expect.
Form_Applications.Application is referring to the application itself. It is not a field, so therefore it is not assignable (at least with a string).
You really haven't provided enough code to draw any real conclusions though. But looking at what you have posted, you definitely need to rethink your approach.
It's to say definitely but you are not doing the same. It looks like you are reading a ComboBox value the same (I will assume Combo64 is the same as 43 and 56) but my guess is that what you are assigning that value to is the problem:
Form_Applications.Application =
Application is not assignable. Is there another field you meant to use there?

Bang Notation and Dot Notation in VBA and MS-Access

While perusing an application that I'm documenting, I've run across some examples of bang notation in accessing object properties/methods, etc. and in other places they use dot notation for what seems like the same purpose.
Is there a difference or preference to using one or the other? Some simple googling only reveals limited information on the subject with some people actually using it in opposite cases. Perhaps there is a coding standards section from MS somewhere that indicates the method of madness?
Despite the (formerly) accepted answer to this question, the bang is not in fact a member or collection access operator. It does one simple and specific thing: The bang operator provides late-bound access to the default member of an object, by passing the literal name following the bang operator as a string argument to that default member.
That's it. The object doesn't have to be a collection. It doesn't have to have a method or property called Item. All it needs is a Property Get or Function which can accept a string as the first argument.
For much more detail and proof, see my blog post discussing this: The Bang! (Exclamation Operator) in VBA
The bang operator (!) is shorthand for accessing members of a Collection or other enumerable object, such as the Fields property of an ADODB.Recordset.
For example, you can create a Collection and add a few keyed items to it:
Dim coll As Collection
Set coll = New Collection
coll.Add "First Item", "Item1"
coll.Add "Second Item", "Item2"
coll.Add "Third Item", "Item3"
You can access an item in this collection by its key in three ways:
coll.Item("Item2")
This is the most explicit form.
coll("Item2")
This works because Item is the default method of the Collection class, so you can omit it.
coll!Item2
This is short-hand for both of the above forms. At run-time, VB6 takes the text after the bang and passes it as a parameter to the Item method.
People seem to make this more complicated than it should be, which is why it's hard to find a straightforward explanation. Usually the complications or "reasons not to use the bang operator" stem from a misunderstanding of how simple it actually is. When someone has a problem with the bang operator, they tend to blame it instead of the real cause of the problem they are having, which is often more subtle.
For example, some people recommend not using the bang operator to access controls on a form. Thus, Me.txtPhone is preferred over Me!txtPhone. The "reason" this is seen as bad is that Me.txtPhone will be checked at compile-time for correctness, but Me!txtPhone won't.
In the first case, if you mistype the code as Me.txtFone and there is no control with that name, your code won't compile. In the second case, if you wrote Me!txtFone, you won't get a compile error. Instead, your code will blow up with a run-time error if it reaches the line of code that used Me!txtFone.
The problem with the argument against the bang operator is that this problem has nothing to do with the bang operator itself. It's behaving exactly the way it's supposed to.
When you add a control to a form, VB automatically adds a property to your form with the same name as the control you added. This property is part of the form's class, so the compiler can check for typos at compile-time if you access controls using the dot (".") operator (and you can access them using the dot operator precisely because VB created a named control property for you).
Since Me!ControlName is actually short-hand for Me.Controls("ControlName")1, it should not be suprising that you don't get any compile-time checks against mistyping the control name.
Put another way, if the bang operator is "bad" and the dot operator is "good", then you might think
Me.Controls("ControlName")
is better than
Me!ControlName
because the first version uses a dot, but in this case, the dot isn't any better at all, since you are still accessing the control name via a parameter. It's only "better" when there is an alternative way to write the code such that you will get compile-time checking. This happens to be the case with controls due to VB creating properties for each control for you, and this is why Me.ControlName is sometimes recommended over Me!ControlName.
I had originally stated that the Controls property was the default property of the Form class, but David pointed out in the comments that Controls isn't the default property of Form. The actual default property returns a collection that includes the contents of Me.Controls, which is why the bang short-hand still works.
Couple gotchas to serve as addenda to the two exceptional answers already posted:
Accessing recordset fields in forms vs. reports
The default item of Form objects in Access is a union of the form's Controls collection and the form recordset's Fields collection. If the name of a control conflicts with the name of a field, I'm not sure which object is actually returned. Since the default property of both a field and a control is their .Value, it's often a "distinction without a difference." In other words, one normally doesn't care which it is because the values of the field and control are often the same.
Beware of naming conflicts!
This situation is exacerbated by Access's Form and Report designer defaulting to naming bound controls the same as the recordset field to which they are bound. I've personally adopted the convention of renaming controls with their control type prefix (e.g., tbLastName for the text box bound to the LastName field).
Report recordset fields aren't there!
I said earlier the Form object's default item is a collection of Controls and Fields. However, the Report object's default item is only its collection of Controls. So if one wants to refer to a recordset field using the bang operator, one needs to include that field as the source for a (hidden, if desired) bound control.
Beware conflicts with explicit form/report properties
When one adds controls to a form or report, Access automatically creates properties that refer to these controls. For example, a control named tbLastName would be available from a form's code module by referring to Me.tbLastName. However, Access will not create such a property if it conflicts with an existing form or report property. For example, assume one adds a control named Pages. Referring to Me.Pages in the form's code module will return the form's Pages property, not the control named "Pages".
In this example, one could access the "Pages" control explicitly using Me.Controls("Pages") or implicitly using the bang operator, Me!Pages. Be aware, though, that using the bang operator means that Access might instead return a field named "Pages" if one exists in the form's recordset.
What about .Value?
Though not explicitly mentioned in the question, this topic came up in the above comments. The default property for Field objects and most "data-bindable"¹ Control objects is .Value. Since this is the default property, VBA will implicitly return the .Value property's value when it does not make sense to return the object itself. Thus, it's common practice to do this...
Dim EmployeeLastName As String
EmployeeLastName = Me.tbLastName
...instead of this...
EmployeeLastName = Me.tbLastName.Value
The above two statements produce identical results because EmployeeLastName is a string.
Beware the subtle .Value bug when keying dictionaries
There are some cases where this convention can cause subtle bugs. The most notable--and, if memory serves, only--one I've actually run into in practice is when using the value of a Field/Control as a Dictionary key.
Set EmployeePhoneNums = CreateObject("Scripting.Dictionary")
Me.tbLastName.Value = "Jones"
EmployeePhoneNums.Add Key:=Me.tbLastName, Item:="555-1234"
Me.tbLastName.Value = "Smith"
EmployeePhoneNums.Add Key:=Me.tbLastName, Item:="555-6789"
One would likely expect that the above code creates two entries in the EmployeePhoneNums dictionary. Instead, it throws an error on the last line because we are trying to add a duplicate key. That is, the tbLastName Control object itself is the key, not the value of the control. In this context, the control's value does not even matter.
In fact, I expect that the object's memory address (ObjPtr(Me.tbLastName)) is likely what's being used behind the scenes to index the dictionary. I did a quick test that seems to bear this out.
'Standard module:
Public testDict As New Scripting.Dictionary
Sub QuickTest()
Dim key As Variant
For Each key In testDict.Keys
Debug.Print ObjPtr(key), testDict.Item(key)
Next key
End Sub
'Form module:
Private Sub Form_Current()
testDict(Me.tbLastName) = Me.tbLastName.Value
Debug.Print ObjPtr(Me.tbLastName); "..."; Me.tbLastName
End Sub
When running the above code, exactly one dictionary item is added each time the form is closed and re-opened. Moving from record to record (and thus causing multiple calls to the Form_Current routine) does not add new dictionary items, because it is the Control object itself indexing the dictionary, and not the Control's value.
My personal recommendations/coding conventions
Over the years, I've adopted the following practices, YMMV:
Prefix Form/Report control names with control type indicators (e.g., tbTextBox, lblLabel, etc.)
Refer to Form/Report controls in code using Me. notation (e.g., Me.tbLastName)
Avoid creating table/query fields with problematic names in the first place
Use Me! notation when there are conflicts, such as with legacy applications (e.g., Me!Pages)
Include hidden report controls to gain access to report Recordset field values
Explicitly include .Value only when the situation warrants the added verbosity (e.g., Dictionary keys)
¹ What's a "data-bindable" control?
Basically, a control with a ControlSource property, such as a TextBox or ComboBox. A non-bindable control would be something like a Label or CommandButton. The default property of both a TextBox and ComboBox is .Value; Labels and CommandButtons have no default property.

Should query languages have priority of operator OR higher than priority of AND?

Traditionally most programming languages have priority of AND higher than priority of OR so that expression "a OR b AND c" is treated as "a OR (b AND c)". Following that idea search engines and query/addressing languages (css,xpath,sql,...) used the same prioritization. Wasn't it mistake ?
When dealing with large enough data, that prioritization is inconvenient because it makes it impossible to create reusable query context without use of parentheses. It is more convenient to create context by using AND and then union results within that context by using OR. It is even more convenient if space is used as AND operator and comma is used as OR operator.
Examples:
When searching the internet for airline tickets to bahamas in november or december it would be more convenient to type "airline ticket bahamas november,december" instead of "airline ticket bahamas november", "airline ticket bahamas december" or "airline ticket bahamas (november,december)"
In CSS if we need to set style red of 2 elements, we have to do that: body.app1 div.d1 td.phone span.area, body.app1 div.d1 td.fax span.area{color:red} essentially duplicating prefix body.app1 div.d1 and suffix span.area
If priority of OR was higher than AND we would write this in CSS: body.app1 div.d1 td.phone,td.fax span.area{color:red}
Of course, this idea can be developed into having 2 operators OR one with higher priority than AND and one with lower, for example ',' is higher, ';' is lower, but in many cases languages don't have spare symbols to extend that way and also existing priority of "," where it's used is low.
Considering the fact that the background of OR and AND is from mathematical logic where they have well defined precedence, you can not violate that precedence in your design without confusing a VAST majority of the users.
I'd rather have consistency everywhere, in code, SQL, search queries, so that I won't have to remember which way it goes in this particular situation.
I think that you are missing the point of the priority of operators. They are there merely as a convenience to the programmer/book writer. The use of the order of operations makes it so that certain clauses can be written without parens, but the use of parens makes sure the reader knows exactly what the code is doing, especially when different languages have different order of operations.
I don't know of any language which does this, but perhaps it should be an error to have AND and OR combined without parentheses. This is a very common cause of stupid errors.
When Boolean operators are used to join logical statements, the "and" operator should have precedence over "or". I think the point of confusion is that many query languages implicitly form logical statements from nouns but don't make clear what those statements are.
For example, "foo & bar" might be interpreted accepting only pages where both of the following are true:
The page contains an item that matches "foo".
The page contains an item that matches "bar".
The query "foo | bar" might be interpreted to evaluate the above conditions and accept any page where either condition holds true, but it could also be interpreted as involving a single condition:
This page contains an item that matches either "foo" or "bar".
Note that in the simple "foo | bar" case it wouldn't matter which interpretation one chose, but given "foo & moo | bar", it would be impossible to adopt the latter interpretation for the | operator without giving it priority over the & operator unless one interpreted foo & moo as meaning:
This page contains an item that matches both "foo" or "moo".
If the arguments to & included wildcards, such an interpretation might be meaningful (e.g. foo* & *oot might mean that a single item must start with "foo" and ends with "oot", rather than meaning that the page had to have an item that starts with "foo" and a possibly-different item that ends in "oot"), but without such wildcards, there are no items any page could contain that match both "foo" and "moo", and thus no page could contain such an item.
Perhaps the solution would be to have separate operators to join items versus joining pages. For example, if &&, &&!, and || join pages, while &, &!, and | join things to be matched, then foo && bar || moo && jar || quack && foo* | m* & *l &! *ll would match every page that contains both "foo" and "bar", every page that contains both "moo" and "jar" as well as every page which contains the word "quack" and also contains a word that starts with "foo", or that starts with "m", ends with "l", and doesn't end with "ll".
Ironically, in your first example you implicitly use the AND with higher priority, since
airline tickets bahama november
is surely to be understood like, for example
.... WHERE transport = "AIR" AND target like "%bahamas%" AND month = "Nov"
This exposes nicely the silliness of your idea.
The point is, it is always possible to come up with queries that are longer if precedences are like they are, and would be shorter with alternate precedences. Just like it would be possible to come up with arithmetic expressions that could be written with less parentheses if addition had a higher precedence than multiplication. But this in itself is no sufficient reason to alter the behaviour.

Avoiding Language Keyword Conflicts

How do you guys avoid keyword conflicts in your language?
For example, I'm creating a class (VB 2008) to hold all the configuration variables for some reports we generate. Naturally, one of the variables is "Date". And of course you can't have anything named the same as a keyword. In VB 2008 you do have the option of surrounding a conflicting word with []'s and fix it but I've always seen that as a hack. Any suggestions? What are your names to get around common keywords?
Code to help visualize...
Dim m_Title As String
Dim m_Date As String
Public Property Title() As String
Get
Return m_Title
End Get
Set(ByVal value As String)
m_Title = value
End Set
End Property
Public Property [Date]() As String
Get
End Get
Set(ByVal value As String)
End Set
End Property
Probably think about more specific nature of the variable?
From your example, the "Date" can be "Created Date" or "Posted Date" or anything else. If you find your variable names too trivial, you may be oversimplifying (or even obfuscating) your code. Help your coworkers by creating a clear but concise variable names.
Don't look at [Date] as a hack; if your property represents a date, it should be called Date. Use the tools you have available to get the job done. Personally I feel that properties that have the names they do only to get around such conflicts are more of a hack, since you will get to deal with it every time you use the property.
misspell your variable names!
On .NET, it is reasonable to consider the Common Language Specification (CLS) as the lowest common denominator that you should cater to. This is documented in ECMA-335 "Common Language
Infrastructure (CLI) Partitions I to VI". Here's what it says specifically about names; a note in CLS Rule #4 (8.5.1 "Valid names"):
CLS (consumer): Need not consume types that violate CLS Rule 4, but shall have a mechanism to allow access to named items that use one of its own keywords as the name.
So no, it's not really a hack, but a definite rule. The reason why it's there is that, as .NET is extensible as far as languages targeting it go, you can never avoid name clashes. If you cover C#, there's VB. If you cover C# and VB, there's C++/CLI. If you cover all those, there's F# and Delphi Prism. And so on. Hence why it is mandated by CLS that languages provide a way to escape their keywords as identifiers; and all languages I've listed provide some way to do so (and thus are compliant CLS consumers).
In general, it is still considered good manners to avoid clashes with either C# or VB non-context keywords, mainly because those two languages are the most popular by a very large margin. For example, it is the reason why it's HashSet and not just Set - the latter is a VB keyword. The full listings are:
C# keywords
VB keywords
Most languages have something to escape any reserved words. C# has # so you can use #class as an argument name (something MVC adopters are learning).
If the domain states that a certain word be used to describe it then that is what the escaping of reserved words is there for. I wouldn't be afraid to escape reserved words to get my model close to the domain even if it means more typing - the clarity is worth it!
To avoid naming conflicts with keywords, I simply don't use keywords.
In your case, Date. Date of what? If I had to maintain your application that would probably be the first thing I'd ask. The great thing about keywords is that they're completely generic, something a variable name should never be.
There is no silver bullet, but modern languages help a lot with better abilities to manage namespaces.
In my case, I curse the fact that C has an 'index' command.
"Date_" or "_Date".
This is one question where Perl dodges the question entirely.
Variables always have one of $%#*&, the only things that can conflict are Globs/Handles, and subroutines.
Even that isn't much of a problem because Globs/Handles aren't used very much any more.
Subroutines and keywords are very much the same in Perl. If you need to get at the built-in subroutine/keyword you can get at it by appending CORE::, for example CORE::dump.
Really I think the only keywords you would have a problem with are sub, my, local, and 'our', because those keywords are parsed very early in parser. Note that you can still create a sub with those names, it just won't work without specifying the full name, or from a blessed reference, or with a symbolic reference.
{
package test;
sub my{ print "'my' called using $_[-1]\n" };
sub new{ bless {}, $_[0] };
sub sub{ print "'sub' called using $_[-1]\n" };
sub symbolic{
*{__PACKAGE__.'::'.$_[1]}{CODE}->('symbolic reference');
}
my $var; # notice this doesn't call test::my()
}
package main;
my $test = test->new;
# Called from a blessed reference
$test->my('blessed reference');
$test->sub('blessed reference');
print "\n";
# Called using the full name
test::my('full name');
test::sub('full name');
print "\n";
# Called using a symbolic reference
$test->symbolic('my');
$test->symbolic('sub');
Output:
'my' called using blessed reference
'sub' called using blessed reference
'my' called using full name
'sub' called using full name
'my' called using symbolic reference
'sub' called using symbolic reference