Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I'm tempted to create a final class CaseInsensitiveString implements CharSequence.

This would allow us to define variables and fields of this type, instead of using a regular String. We can also have e.g. a Map<CaseInsensitiveString, ?>, a Set<CaseInsensitiveString>, etc.

What are some of the pros and cons of this approach?

share|improve this question
    
Potential concerns: space, need for interning, performance, garbage collectibility, etc. –  polygenelubricants Jul 6 '11 at 6:40

6 Answers 6

up vote 26 down vote accepted

Case insensitivity is a property of the comparison, not of the object (*). You'll want to compare the same string independently of the case or not depending on the context.

(And you have a whole kind of worms as what is a case insensitive comparison depend on the language -- i is upper cased as İ in Turkish -- and even the context -- depending on the word and the dialect ß can be uppercased as SS or SZ in German.)

(*) It can be a property of the object containing the string, but that is somewhat different of being a property of the string itself. And you can have an class which has no state excepted a string, and comparing two instances of that class will use a case insensitive comparison of the string. But that class won't be a general purpose string as it won't provide methods expected for a general purpose strings and will provide methods which aren't. This class won't be called CaseInsensitiveString but PascalIdentifier or whatever is pertinent to describe it. And BTW, the case independent comparison algorithm will most probably be provided by its purpose and be locale independent.

share|improve this answer
1  
So would you recommend a TreeSet<String> using String.CASE_INSENSITIVE_ORDER over a HashSet<CaseInsensitiveString>? Note that using TreeSet means O(log n) for contains. Moreover, this comparator is inconsistent with equals, meaning that the resulting TreeSet doesn't obey the general Set contract (i.e. it may contains(x), even though it has no element that is equals to x). –  polygenelubricants Jul 6 '11 at 10:53
    
Since the mid 90, the generic hash tables I've designed takes both an hash function and an equality function as generic parameters with a default deduced from the key type. (If it isn't the case for those provided by the Java library, I'll risk the explanation that they were designed by someone more familiar with OO programming than generic programming, typing strongly the type with those operations is something you need to do in OOP but a code smell in GP). –  AProgrammer Jul 6 '11 at 11:42
    
@AProgrammer The Java collections use the equals() implementation on each object. There is a default implementation, which any object can override. I don't think you can define the hash, but then I've never tried to - the tables always worked fine without worrying about it (one reason I like Java over C++ :)). –  Michael K Jul 6 '11 at 13:06
1  
@AProgrammer - I disagree with "Case insensitivity is a property of the comparison, not of the object", and with "maybe the object but not the string" proviso. This may describe how things are, but the question is about a proposed change to how things are. In modulo 3 arithmetic, 2 is shorthand for { ..., -4, -1, 2, 5, 8, 11, ... }. The notation represents an abstraction, but isn't the same thing as the abstraction. Why can't 'H' represent the abstraction { 'h', 'H' }? Characters don't exist in the computers memory at all - whether a code represents 'H' or { 'h', 'H' }, it's an abstraction. –  Steve314 Jul 10 '11 at 22:17
1  
@AProgrammer - on the second paragraph, I probably agree though. At the very least, it would imply English case-insensitive strings, Turkish case-insensitive strings, etc etc. A class with subclasses or an i18n option, IOW. And then you get the double dispatch issue (how to compare two case-insensitive strings with different language options). I guess that's back to "property of the comparison". Damn! –  Steve314 Jul 10 '11 at 22:26

Just off the top of my head:

Pros:

  • Makes a lot of code self-documenting, e.g:
    • bool UserIsRegistered(CaseInsensitiveString Username)
  • May streamline comparisons
  • May remove the potential for comparison bugs

Cons:

  • Might be a waste of time
    • people can just convert regular strings to lowercase if they need case-insensitive comparisons
  • Using it for front-end code will cause capitalization problems
    • For example, if you use CaseInsensitiveString to store a username, even though it makes sense to have case-insensitive back-end comparisons, the front-end code will display the user's name as "bob smith" or "BOB SMITH"
  • If your code base already uses regular strings, you will have to go back and change them or live with inconsistency
share|improve this answer
4  
Depending on the implementation, your second "Cons" point doesn't have to be valid - you can implement CaseInsensitiveString to store case-sensitively and merely override the comparison operators. –  tdammers Jul 6 '11 at 6:00
1  
@tdammers: if the CaseInsensitiveString is stored with case and then with the comparison operator overrided, it reinforces the point of @AProgrammer that the comparison operator could have been decoupled from the whatever string object. –  rwong Jul 10 '11 at 12:09
3  
@tdammers - some things already work similarly. Windows filesystems preserve case, for example, but are case insensitive for comparisons. It's not a bad system, but can cause confusion when you want to "rename" something to change the case. Basically, you still sometimes need case-sensitive comparison to avoid making bad judgements about whether a rename is making a genuine change - and if there's one special case, maybe there's others too. –  Steve314 Jul 10 '11 at 22:23
    
@rwong: I agree. Best thing would be explicit case-insensitive comparisons where needed. However, sometimes you want strings to behave like SQL strings (with a CI collation), and then preserving case on storage but ignoring case on comparison would be the closest match. –  tdammers Jul 11 '11 at 5:50

CaseInsensitiveString is not a bad idea depends on your use, as long as you don't expect it to work together with String.

You may convert a CaseInsensitiveString to a String, or vice-versa, and that's all you should do.

Problem will happen if you try to do something like

class CaseInsensitiveString {
  private String value;

  public boolean equals(Object o) {
    // .....
    if (o instanceof String) {
      return value.equalsIgnoreCase((String) o);
    }
  }
}

You are doomed to fail if you are going to make your CaseInsensitiveString corporate with normal String, because you will be violating symmetric-ness and transitive-ness for equals() (and other contracts)

However, please ask yourself, in what case you really need this CaseInsensitiveString which it is not suitable to use String.CASE_INSENSITIVE_ORDER ? I bet not many case. I am sure there will be case that worth having this special class, but ask yourself first.

share|improve this answer

Explicitly creating types in your domain/model is very good practice. Like Maxpm said it is self documenting. Also a big plus: people can't (by accident) use wrong input. The only negative thing it has would be that it will scare off junior (and even some medior) programmers.

share|improve this answer

A CaseInsensitiveString class and its helpers add a lot of code and they will make everything less readable than the String.toLoweCase() method.

CaseInsensitiveString vaName1 = new CaseInsensitiveString('HeLLo');
//... a lot of lines here
CaseInsensitiveString vaName2 = new CaseInsensitiveString('Hello');
//... a lot of lines here
if (varName1.equals(varName2)) ...

is more complex, less self documenting, and less flexible than

String vaName1 = 'HeLLo';
//... a lot of lines here
String vaName2 = 'Hello';
//... a lot of lines here
if (varName1.toLowerCase().equals(varName2.toLowerCase())) ...
share|improve this answer

The most frequently used implementations on the web are case sensitive - XML, JavaScript. In terms of performance, it is always best to use the most appropriate function/property/object for each case.

If you are dealing with structures - XML or JS or similar, case sensitivity is important. It is much faster using system libraries.

If you are dealing with data in a database, as mentioned above the database indexing shall be used for case sensitive/insensitive strings.

If you are handling data on the fly, it is important to make the necessary conversion cost calculation for each string. It is probable that the strings should be compared or sorted somehow.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.