last day (15 days later) » 

08:50
-4
A: Is it okay to have objects that cast themselves, even if it pollutes the API of their subclasses?

Mike NakisWhat you are doing is perfectly legitimate. Do not pay attention to the naysayers who merely reiterate dogma because they read it in some books. Dogma has no place in engineering. I have employed the same mechanism a couple of times, and I can say with confidence that the java runtime could ha...

This is my preferred answer right now, and not just because it's saying I'm doing the right thing. The circumstances you're describing (closely-coupled classes, small hierarchy) sound just like what I'm doing. Maybe I went too far by using my silly, disparate method examples, but the point is my subclasses actually do share a good deal of functionality, but also branch significantly (somewhat like Member), so I think this answer works here.
It's legitimate if you designed yourself into a box, sure. That's the problem with a lot of these types of questions. People make decisions in other areas of the design which force these type of hackish solutions when the real solution is to figure out why you ended up in this situation in the first place. A decent design won't get you here. I'm currently looking at a 200K SLOC application and I'm not seeing anywhere that we needed to do this. So it isn't just something people read in a book. Not getting in these types of situations is simply the end result of following good practices.
@Dunk I just showed that the need for such a mechanism exists for example in the java.lang.reflection.Member hierarchy. The creators of the java runtime got in this type of situation, I don't suppose you would say they designed themselves into a box, or blame them for not following some kind of best practices? So, the point I am making here is that once you have this type of situation this mechanism is a good way to improve things.
I'm all for avoiding this situation if I can, I just can't figure out a better way to represent a type hierarchy where two subclasses share a lot of members, but also diverge quite a bit such that they need separate handling.
@MikeNakis The creators of Java have made plenty of bad decisions, so that alone doesn't say much. At any rate, using a visitor would be better than doing an ad-hoc test-then-cast.
08:50
@codebreaker-A possible strategy to come up with a better design would be to write some Use-Cases for just your Base class. Try to do a quick design based purely on the Use-Cases. Try not to let the existing design influence your new design. I'll bet you solve your problem. I find a 4x6 whiteboard indispensable for these types of situations.
@Doval C# has an equivalent hierarchy starting with System.Reflection.MemberInfo which is extended by FieldInfo, MethodInfo, etc. I think it is highly unlikely that the creators of C# made the same bad decisions.
Additionally, the example is flawed. There is a Member interface, but it only serves to check the access qualifiers. Typically, you get a list of methods or properties and use that directly (without mixing them, so no List<Member> appears), so you do not need to cast. Note that Class does not provide a getMembers() method. Of course, a clueless programmer might create the List<Member>, but that would make as little sense as making it a List<Object> and adding some Integer or String to it.
@Mike-There are special case situations where these methods are useful. Particularly when serializing/deserializing objects and for being able to programmatically examine classes when building productivity tools like Intellisense. Just because something exists doesn't mean it is a good idea or was intended to be used for normal purposes.
@MikeNakis "A lot of people do it" and "Famous person does it" are not real arguments. Antipatterns are both bad ideas and widely used by definition, yet those excuses would justify their use. Give real reasons for using some design or another. My issue with ad-hoc casting is that every user of your API has to get the casting right every single time they do it. A visitor only needs to be correct once. Hiding the casting behind some methods and returning null instead of an exception doesn't make it much better. All else being equal, the visitor is safer while doing the same job.
@SJuan76 yes, Member is an interface. The common base class is AccessibleObject. Same thing. And in C# System.Reflection.MemberInfo is an actual class, not an interface.
08:50
@Doval-I agree with you conceptually but Visitor does usually obfuscate things. "Easy to understand" is a very close 2nd to "It works" in my book. Like I said, I looked at my current code and about the only places where we even care about the type is when using .Net functionality (e.g. XmlSerializer, CompareTo, QueueUserWorkItem). Other than that we call GetType for some log entries to report which derived class is creating the log entry, only use typeof when converting strings to Enums, and not much more. So I'm convinced this is solvable by an easy to understand design.
@SJuan76 and yes, java.lang.Class does not have getMembers(), but we do often need to put all members in a list. And in C# System.Reflection.MemberInfo has MemberInfo[] GetMembers(), MemberInfo[] FindMembers(), etc.
@Doval I did not say "A lot of people do it", nor "Famous person does it". I said "look here, a real world scenario right under your nose that has a demonstrably workable solution using precisely such a construct". Actually, two manifestations of the same construct in two different languages.
@MikeNakis of course it is somehow legitimate - since the language allows it. Many things are legitimate, but that doesn't mean, that it makes sense do to such things. It is like putting training wheels on a car with three tires to make it drive somehow.
@ThomasJunk no, it is more like someone using a perfectly good solution to a rarely occurring but well defined problem, and everyone laughing at them because they have never seen such a thing before.
The solution may be sound in this case, but the problem is artificial, since with better design it would not occur. And no: no one is laughing.
And because it is a sound solution, I did not downvote your answer, even if it doesn't really help either.
@ThomasJunk the fact that the creators of the java runtime and the C# runtime independently arrived at the same design is a very strong indication that there is no better design, or that a design which would look better in the eyes of a few purists would in fact be worse in the eyes of the far more people who would actually have to use it. Yeah, pragmatism is a bitch.
08:50
I'm unclear why you've rejected the visitor pattern. This is the traditional OO route to deal with precisely the scenario you're describing.
Also RE your example, I'm not sure what situation you'd say "I want to do one, field-specific thing if I'm holding a field, and another, method-specific thing, if I'm holding a method, but I don't know which I have".
@BenAaronson the visitor pattern is one way to go, but it is a hassle. I mean, by that token, instanceof-and-cast is also a way to go, and even less of a hassle than the visitor pattern. We did not suggest that the self-casting mechanism achieves something which cannot be achieved otherwise, we are only proposing a means of reducing hassle.
@BenAaronson a trivial situation where you would want to do this: suppose you have all the members of a class in a collection, and you just want to print their definitions.
@MikeNakis Visitor pattern only needs to be a hassle if you want to be able to access or visit non-public members, which doesn't seem to be the case here.
@MikeNakis: That Java and C# do it is no indication that there is no better design. Java didn't put reflection in originally, so it would not be surprising if they needed an ugly hack to make it work when they bolted it on later. It isn't anti-pragmatic to reject ugly hacks if you don't need them.
09:34
@C
hmm this was a very interesting discussion. we have all coded ourselves in this hole before.. specially when we were new to software... coding yourself into a hole is fine and dandy... but I think the real problem stems from lack of proper unit testing. Once you started seeing your model diverge, you could have handled it earlier.

last day (15 days later) »