Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java generics with 'semantics', is this possible?

Tags:

Firstly apologies if I'm using the wrong term by picking the word 'semantics.'

I'm a big fan of generics in Java for all the obvious reasons. It helps me enormously as I work with a huge variety of odd bits of code and I often have to go back to old stuff. Today I found myself with a classic parameter misplacement bug which I probably wouldn't have written in the pre-generic days - they have made me a bit lazy.

I'd like to know if there is a language feature, either in Java or perhaps as a similar concept in other languages, which takes the type safety of generics and extends it to a kind of semantic safety. Specifically I want to help trap the kind of errors which result from putting the right thing in the wrong place.

A simple example:

Map<String, String> myMap = new HashMap<String, String>();
String myKey = "key";
String myVal = "value";
myMap.put(myVal, myKey);

Which no compiler will catch. I could subclass Stringmake wrappers to give me a Key type and a Value type, I suppose. I could name my variables to indicate their use (as I've done in this example). What else?

So my questions are:

  • out of academic interest, what is this concept called and what languages have this feature?
  • In the absence of any such language feature, what are the best practices to avoid this kind of error?

Thanks

like image 356
Tim Avatar asked Jul 19 '11 18:07

Tim


3 Answers

I have always used maps that have two different types for the key and value, never the same types. I suppose there are times when you would want to use the same type for the key and value as in your example. I can't think of any languages off the top of my head that have this feature.

Actually I have used Clojure before and for maps it uses a keyword for the key which looks like :key and then the value is just whatever the value is. It makes it clearer but now i'm dabbling into functional programming which is not really the question you were asking. Check out Lisp-like languages.

I think its just a case of not getting them mixed up, Java certainly cannot enforce this kind of checking.

Best advice would be to use different types for the key and value so the compiler can detect the type error, or name the key and value variables explicitly as you have done.

like image 108
adamjmarkham Avatar answered Oct 12 '22 11:10

adamjmarkham


You can't subclass String. You can create your own classes, though, and use them. So if you are mapping Persons to Roles, for instance, you can define a Person like

class Person {
  String id;
  String firstName;
  String lastName;
   ...
}

and a Role like

class Role {
    int id;
    String name;
}

(Note these will need to define an equals and hashcode method)

and have a mapping from person to role like:

Map<Person, Set<Role>> myMap = new HashMap<Person, Set<Role>>();

so that the type system enforces what you can put where (as opposed to having a map of strings to sets of ints). Not sure what this is called but "Domain Objects" and "Abstract Data Types" seem related.

In the absence of type-checking the fallback is to write unit tests.

like image 27
Nathan Hughes Avatar answered Oct 12 '22 11:10

Nathan Hughes


You could use a more extensive type system, avoiding using the same type in parameter lists.

i.e.

Map<Key, Value> myMap = new HashMap<Key, Value>();
Key myKey = // some key
Value myVal = // some value
myMap.put(myVal, myKey); //compiler error

On some level you need to explain the concepts and how they interact with operations to have the language check anything, interested in whether there are any alternative approaches out there.

like image 45
brabster Avatar answered Oct 12 '22 11:10

brabster