Java Forum / General / December 2005
Tagging interfaces
VisionSet - 29 Nov 2005 13:06 GMT Why exactly are they bad?
I have a entity, a collection of which is to be associated with an object that has no need to call any methods on or know anymore than the entity is of a certain type. These entities are then passed back to the object that instantiated them which can cast to the concrete type to do something useful with them. So a tagging interface seems to fit the bill for my entity.
-- Mike W
klynn47@comcast.net - 29 Nov 2005 14:50 GMT Jeffrey Schwab - 29 Nov 2005 16:41 GMT > Why exactly are they bad? > [quoted text clipped - 3 lines] > instantiated them which can cast to the concrete type to do something useful > with them. So a tagging interface seems to fit the bill for my entity. Please correct me if I have misunderstood anything:
Each "Entity" requires type-specific processing, but you want the code for all the processing, for all the different types, to be defined in one "Master" object.
The Master, which actually created all of these Entities, forgets the Entities' exact types at some point. It therefore wants them to be "tagged," possibly by having them implement empty but nominally different interfaces.
This sounds like a perfect case for polymorphism. Forget all the tagging interfaces. Have all the Entities implement just one interface, and each concrete Entity type can implement the interface differently. If you really want to keep the processing code in the Master object, let each concrete Entity type just immediately invoke a type-specific callback method in the Master.
If this isn't clear, or doesn't sound like a good idea, let me know & I'll whip up some example code.
VisionSet - 29 Nov 2005 16:47 GMT > > Why exactly are they bad? > > [quoted text clipped - 9 lines] > for all the processing, for all the different types, to be defined in > one "Master" object. The number of types (tagged types) and number of master objects is a 1:1 relationship In fact there is only ever likely to be one entity type and one master object, but that is not important. We shall assume other types may exist at some point.
> The Master, which actually created all of these Entities, forgets the > Entities' exact types at some point. It therefore wants them to be > "tagged," possibly by having them implement empty but nominally > different interfaces. The tagging is merely type safety mechanism so the surrogate collector can only collect a certain type, and the master only gets back what it expects.
-- Mike W
Jeffrey Schwab - 29 Nov 2005 18:24 GMT >>>Why exactly are they bad? >>> [quoted text clipped - 35 lines] > The tagging is merely type safety mechanism so the surrogate collector can > only collect a certain type, and the master only gets back what it expects. Wouldn't it be easier, and make your intent clearer, to use generics?
VisionSet - 29 Nov 2005 19:14 GMT > > The tagging is merely type safety mechanism so the surrogate collector can > > only collect a certain type, and the master only gets back what it expects. > > Wouldn't it be easier, and make your intent clearer, to use generics? I'll still need a type, no?
Collection<? extends TagIntf>
-- Mike W
Jeffrey Schwab - 29 Nov 2005 19:27 GMT >>>The tagging is merely type safety mechanism so the surrogate collector > [quoted text clipped - 9 lines] > > Collection<? extends TagIntf> You said you wanted the surrogate collector to "only collect a certain type." You should be able to use this type as the parameter for the generic container, e.g. Collection<Entity>. No?
VisionSet - 29 Nov 2005 21:24 GMT > >>Wouldn't it be easier, and make your intent clearer, to use generics? > > [quoted text clipped - 5 lines] > type." You should be able to use this type as the parameter for the > generic container, e.g. Collection<Entity>. No? I said I wanted to assume that the 1 type may grow to include others, although only 1 type would be used in any 1 instance of the program, but that is irrelevent I want the code to be able to support that eventuallity. Hence the tagging interface.
But I'd heard there really was no defence for tagging interface approach, and that is is merely a hack to allow introspection. But when you are faced with the situation where an objects references are collected at various places because that is where they naturally belong, and that is the best way to manage there existence, but no methods are called on them, and you want to decouple their logic, then this seems like an okay use to me.
-- Mike W
Andrew McDonagh - 29 Nov 2005 23:32 GMT > Why exactly are they bad? > [quoted text clipped - 6 lines] > -- > Mike W Before 1.5, Tagging (or more commonly know as 'Marker') Interfaces were a good way of achieving the same effect as 1.5 Annotations.
They were never bad - mis-understood and therefore mis-used.
Now we have annotations there is certainly less need for them.
Andrew
Chris Smith - 30 Nov 2005 23:27 GMT > Why exactly are they bad? My thoughts on the matter.
If you think of what you're doing as a tag interface, then it's probably a bad idea, at least as of Java 1.5. The reason is that interfaces are part of the type system, and as such they imply a certain relationship between the types of objects that implement them.
There are two ways you can solve this apparent mismatch.
(a) Give up on making the "tag" a type. With Java 1.5, you'd then decide to use an annotation, instead. Annotations don't define type system relationships, but they do allow you to note information about a type that can be used (among other places) dynamically at runtime. For example, if Java were newly designed today, Cloneable and Serializable would probably be annotations, because no one ever keeps a variable of type Serializable or Cloneable.
(b) The other direction: stop thinking of it as a tagging interface, and start thinking of it as a full-fledged type. Even if that type doesn't necessarily need to declare any methods at all (as in your example), it is a type... and it COULD declare methods. Once you're comfortable with that, stop calling it a tagging interface, and stop worrying about bad design. (Of course, if you then think of operations that make sense and are useful to your application on all referents of that type, by all means add them to the interface... especially if this allows you to take advantage of polymorphism.)
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
John C. Bollinger - 01 Dec 2005 02:42 GMT > if Java were newly designed today, Cloneable and Serializable > would probably be annotations, because no one ever keeps a variable of > type Serializable or Cloneable. I do. I at times keep variables and declare method parameters and return types as Serializable in classes that implement Serializable, so as to improve the likelihood that instances can in fact successfully be serialized. Naturally, this tends to involve general-purpose classes where the declared types would otherwise be Object. I haven't done this with Java 1.5 yet, but in a generic class or method I might use Serializable as an upper type bound or (intentionally) in an intersection type. It does not seem that this paradigm ever caught on in the wider world, but it does lead me to accept Serializable as a very reasonable type.
In the context of the larger discussion of tag interfaces, however, the reason that Serializable as an interface makes any sense is that it has special meaning to the VM. A type should convey useful information about objects, and for interfaces without special meaning to the VM, it is my opinion that at least one method is necessary to make the information conveyed useful.
 Signature John Bollinger jobollin@indiana.edu
Chris Smith - 01 Dec 2005 03:18 GMT > In the context of the larger discussion of tag interfaces, however, the > reason that Serializable as an interface makes any sense is that it has > special meaning to the VM. A type should convey useful information > about objects, and for interfaces without special meaning to the VM, it > is my opinion that at least one method is necessary to make the > information conveyed useful. I'm not clear on the details of Mike's case... but if he's being generally accurate in his description, Mike may have a counter-example to your statement.
In his case, Mike is apparently keeping objects in some kind of specialized data structure whose behavior (presumably) only makes sense for objects of that specific type. The type may not have any general new operations to introduce, but in may still imply certain constraints in the way that its objects should be managed. It may even further constrain the implementations of inherited method declarations, such as Object's equals and hashCode. Much like in the Collections API, then, the client code is arranged to know the type when it retrieves the object.
Of course, this new data structure type *could* be written with a type of Object, but that would imply that it works properly and makes sense for all Object references... something that may not actually be the case. I would think this is exactly the right use for a type, new operations or not.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
VisionSet - 01 Dec 2005 16:10 GMT > I'm not clear on the details of Mike's case... but if he's being > generally accurate in his description, Mike may have a counter-example > to your statement. Okay, since I've generated some interest, I'll expand.
I'm attempting to decouple the method of networking from the work that the server does. I have a 2 way socket based network layer that can initiate communication, handle requests and reply with responses in either direction. This Class is passed handler objects which deal with the requests and return something appropriate. In order for the server to pass the correct stuff to specific interested clients the business part of the server must keep references to its clients. These references must know how to locate the client but the business part of the server does not need to know this. So ClientRef has some business stuff and also a Location reference. It is this location reference that can be an empty interface type. The business layer never needs to know anything other than it is some form of locator. The network layer created the Location and when it gets it back will know how to interrogate it for the address. I suppose this is by the by, but I guess port and ip address is only ever going to be the information you need to locate. But I don't know that for sure, so the principle stands.
-- Mike W
John C. Bollinger - 03 Dec 2005 03:57 GMT >>In the context of the larger discussion of tag interfaces, however, the >>reason that Serializable as an interface makes any sense is that it has [quoted text clipped - 22 lines] > case. I would think this is exactly the right use for a type, new > operations or not. I'm still not entirely clear on the details of Mike's case even after he expanded on it, but I am so far not swayed from my position. My argument on this point is much the same as on the Serializable point: it is incorrect to *do* anything with a reference of a type that has no members, other than simply to hold it and pass it around, because you must then make some assumption about the object that is not ensured by its type. On the other hand, using a tag interface as the type is just as bad as using Object: it implies that any object of the tag interface type is appropriate for use with the application, which is unlikely to be true. (Try passing it a "new YourTagInterface() { void darnMySocks() {}}".) Somewhere, some time, some body is going to have to cast that reference to make use of the object, and therein is the indicator of a problem.
(Of course, if the tag interface extends Serializable, then you can at least expect to be able to serialize instances.... ;-))
 Signature John Bollinger jobollin@indiana.edu
Chris Smith - 03 Dec 2005 04:39 GMT > I'm still not entirely clear on the details of Mike's case even after he > expanded on it, but I am so far not swayed from my position. I'm also not swayed, now that I've read Mike's description... but I think I'm unswayed in the opposite direction as you (if I understand you correctly). In this case, I actually think that Mike should be using Object as the type; no interface, no annotation. The reason is that a "location" may be of pretty much any type, not just one that was designed to work with this data structure. The only requirement is that it is later interpretable by the same piece of code that created it.
I don't share the same hostility you express toward casts. When they are checked at runtime as Java's casts are, casting is just a perfectly normal way of telling the compiler some additional information about a type. It need not be seen as terribly nefarious. In Mike's case as described, using an interface type doesn't just mean modifying classes; it means potentially creating a new class when InetSocketAddress may be perfectly good enough!
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
Chris Smith - 01 Dec 2005 03:26 GMT > > if Java were newly designed today, Cloneable and Serializable > > would probably be annotations, because no one ever keeps a variable of [quoted text clipped - 4 lines] > as to improve the likelihood that instances can in fact successfully be > serialized. Perhaps. I tend to see this as too leaky to be worthwhile. You're impacting a lot of code in order to build something that doesn't provide any additional guarantees. After all, ArrayList implements Serializable yet can't guarantee that it can be serialized.
Worse, though, you impact client code here as well. There are plenty of good reasons to hold references to objects that you know are serializable, and yet not use a serializable type. For example, I often keep references of type List for obvious reasons, yet List does not extend Serializable. I may need to add casts to my code in order to use an API that uses Serializable as a type, and yet there's no good way that I could modify my code to hold variables of type Serializable in the first place.
In the end, I dismiss use of Serializable as a type as being without significant merit. If it could make serialization safe, of course, that would be phenomenal... but it can't. Instead, it only adds more static hurdles to using what is ultimately a runtime-checked feature anyway.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
John C. Bollinger - 03 Dec 2005 03:27 GMT >>> if Java were newly designed today, Cloneable and Serializable >>>would probably be annotations, because no one ever keeps a variable of [quoted text clipped - 9 lines] > any additional guarantees. After all, ArrayList implements Serializable > yet can't guarantee that it can be serialized. I did say I wanted to "improve the likelihood" of being able to serialize instances, not that I wanted to ensure successful serialization. If the approach I describe were ubiquitous then it would be much more effective.
> Worse, though, you impact client code here as well. There are plenty of > good reasons to hold references to objects that you know are [quoted text clipped - 4 lines] > that I could modify my code to hold variables of type Serializable in > the first place. I disagree. For a class whose instances are expected to routinely be serialized, declaring method parameters to be Serializable both reinforces the point with the class' users and provides some degree of compile-time checking. It is incorrect to keep references of a non-Serializable type and nevertheless expect the referenced objects to be Serializable, even if you "know" that they really are, just as it is incorrect to keep references of type Collection and yet assume that the referenced objects are Lists. Indeed, the error is precisely in relying on knowledge about the objects' classes that is not reflected in their references' declared types. Typecasts (of reference types) are usually a sign of this kind of error, with the only exception I can think of being casting to disambiguate an overloaded method invocation.
By the way, the type safe solution in the List example is not to cast, but rather "new ArrayList<SomeSerializableType>(myAnyList)".
(Aside: avoiding most need to engage in the kind of incorrect coding discussed above is by far my favorite aspect of both generics and covariant return types.)
> In the end, I dismiss use of Serializable as a type as being without > significant merit. If it could make serialization safe, of course, that > would be phenomenal... but it can't. Instead, it only adds more static > hurdles to using what is ultimately a runtime-checked feature anyway. No, it can't make serialization safe, because serialization is fundamentally unsafe. I remain convinced, however, that it makes serialization saf*er* -- by making some of the class' expectations explicit in its structure -- and, moreover, that it presents no additional hurdle whatsoever to otherwise typesafe code.
 Signature John Bollinger jobollin@indiana.edu
Chris Smith - 03 Dec 2005 04:29 GMT > I disagree. For a class whose instances are expected to routinely be > serialized, declaring method parameters to be Serializable both [quoted text clipped - 4 lines] > incorrect to keep references of type Collection and yet assume that the > referenced objects are Lists. Even accepting this idea, you are forced to make a choice eventually between several good design ideas. Perhaps it would be good to extend Java to allow type (List & Serializable), in the manner of generic type bounds... but that feature isn't currently available. I'd certainly far rather use List and imply Serializable than use ArrayList just to get the Serializable statically declared.
I just don't see that there's much benefit to half-solving problems of verifiability. It's still not verifiable, and that's the end of the story.
 Signature www.designacourse.com The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer MindIQ Corporation
John C. Bollinger - 06 Dec 2005 04:31 GMT > Perhaps it would be good to extend > Java to allow type (List & Serializable), in the manner of generic type > bounds... but that feature isn't currently available. I'd certainly far > rather use List and imply Serializable than use ArrayList just to get > the Serializable statically declared. Believe it or not, I almost wrote something to that effect myself. I would be downright *delighted* to be able to use intersection types in declarations.
 Signature John Bollinger jobollin@indiana.edu
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|