Adam Schaible

Ranch Hand
+ Follow
since Oct 04, 2007
Merit badge: grant badges
Cows and Likes
Cows
Total received
0
In last 30 days
0
Total given
0
Likes
Total received
0
Received in last 30 days
0
Total given
0
Given in last 30 days
0
Forums and Threads
Scavenger Hunt
expand Ranch Hand Scavenger Hunt
expand Greenhorn Scavenger Hunt

Recent posts by Adam Schaible

From JLS 8.3.2


8.3.2 Initialization of Fields
If a field declarator contains a variable initializer, then it has the semantics of an assignment (�15.26) to the declared variable, and:

If the declarator is for a class variable (that is, a static field), then the variable initializer is evaluated and the assignment performed exactly once, when the class is initialized (�12.4).
If the declarator is for an instance variable (that is, a field that is not static), then the variable initializer is evaluated and the assignment performed each time an instance of the class is created (�12.5).
The example:

class Point {
int x = 1, y = 5;
}
class Test {
public static void main(String[] args) {
Point p = new Point();
System.out.println(p.x + ", " + p.y);
}
}

produces the output:

1, 5

because the assignments to x and y occur whenever a new Point is created.
Variable initializers are also used in local variable declaration statements (�14.4), where the initializer is evaluated and the assignment performed each time the local variable declaration statement is executed.

It is a compile-time error if the evaluation of a variable initializer for a static field of a named class (or of an interface) can complete abruptly with a checked exception (�11.2).

It is compile-time error if an instance variable initializer of a named class can throw a checked exception unless that exception or one of its supertypes is explicitly declared in the throws clause of each constructor of its class and the class has at least one explicitly declared constructor. An instance variable initializer in an anonymous class (�15.9.5) can throw any exceptions.



Basically, when a class is initialized it initializes the fields if they have an assignment statement.
14 years ago

We don't. What concerns?
Note that you don't *have* to extend our base classes. It will just be more work for you if you don't.


My main concern is I like to understand what's happening. I guess it depends on how close this code is to business critical operations, but I'd rather not enter a black-box. I'd just like to be able to debug through everything, and I can't without the source.

Yes. And in a system that evolves over a decade and more, contracts need to change. So, what should we do if we find that the most consistent, coherent way of adding a new feature would require us to add an operation to an existing interface? Serious question.


It sounds like you're using interfaces for your internal contract, and abstract classes for your external contract. That way, if you want to break the internal contract, you can simply modify your base class so your clients code still works.

To answer the question, your clients should be implementing an interface that defines what they program. Your old abstract classes should have an instance of this interface as a private member. Your old abstract class should delegate to this member for all of the custom stuff - this way their code is decoupled from your implementations, and your clients understand their expectations because they are clearly defined in the contract of the interface they implement. Also, you are free to manipulate your implementations because your clients really don't depend on you, you depend on your clients.

Sometime's I'm not the best at explaining on a forum, but this solution really protects your code from being abused, and your clients mis-using your code, and accidentally plugging in to part of your code that wasn't supposed to be public.

You've also said the abstract classes are just there so you can add methods to them and implement them if you choose - not forcing the client code to be modified. Again, read above.

The solution to all "abstract class" problems, in general, is to write an interface that defines the abstract methods and delegate to it's implementation.

It can get tricky with "optional" overrides. One could argue that overriding, in general, is going down the wrong path. If it's an occasional thing, between the two of us we could discover plenty of good solutions fairly quickly - but I do understand overriding is more difficult.

One pattern I've seen is to simply return null if you want the default implementation. While I really hate intentionally returning null and having it mean something, debugging the code is pretty clear.
14 years ago
Jim,

These are two different things. There are thousands of possible scenarios - and I agree it usually doesn't make much sense to return a java.util.Comparable.

It really is a slippery slope - especially with collections and generics. I had a fairly long response but I don't think this forum is the place for a "rules engine" - there are simply too many situations to define, and sometimes the quality of two solutions are roughly equivilent, and the decider is consistency. I think the "process" here is to simply think about all of the possibilities and make the most logical choice.
14 years ago
You'd have to post your code, or be much more descriptive to get a reasonable answer. Also, this should be in the beginner forum.
14 years ago
As far as tests are concerned, I can only test my API code - so I do agree with the doctor analogy, but I can't wash your doctors hands for him.

I don't know if you provide source or not, but I would have concerns as a client extending your implementation - less of a problem if I had the source, but still a problem.

The point of an interface is to layout your contract. In my opinion, once an interface is published, it really shouldn't change. Interfaces should be the "foundation" of your structure.

By extending your abstract classes, you're just choosing to make that your way of sharing your code instead of an interface.

The other (large) problem with extending an abstract class, is that it's usually fairly difficult to quickly and easily "parse" the functionality, and integration points between the child and it's parent.

Using an aggregation/composition model, atleast to me, removes the quagmire of ambiguity. In addition, I feel debugging is much more straight-forward.

Just opinions, but that's what a forum is for!
14 years ago
++Fred's post..

Really, that's the main reason. You will rarely change your list implementation - and if you do it's really not THAT much work to go through your code and fix it...

...but it's dumb to use a concrete implementation anyway, you get absolutely no benefit from returning an implementation type, and as Fred has said, your objects are less likely to play nice with API's that like Collections, Lists, Maps, etc.
14 years ago
this is the method I'm talking about:



What's the return type?

This compiles for me:



I had to remove the return -2... it's unreachable as said before, but has nothing to do with the return type.
14 years ago
I'm aware of the abstract test pattern, and have occasionally used it.

As far has having a full suite of unit tests, I 100% agree - but it's not reality for a large portion of my clients. They would all love to have it, but most of the business budget people don't see it has a value-adding effort (no matter how many times they are told otherwise).


Make getWord() protected. Problem solved.



I didn't really explain myself well enough here. I really don't want to expose intermediate calculations here. Lets say I extend your abstract template, put it in my own package - it definately does have access to getWord() (obviously, it has to implement it).

I design API's to be used by all level's of developers - if something CAN be abused, it will be - using extends begs to be abused.

I know, I know - if everyone uses your software how you want it to be used, it's not dangerous at all - but when people begin to depend on parts of your implementation that you have exposed because you extended something, you're now tied to it.

People can override ALL of your template methods - then send it back into your API.
You can't make your abstract class final (obviously, but you may want)

For the test pattern, it is useful - and using extends in this case isn't that dangerous (generally your tests test YOUR software, thus you have complete control over both the tests and the code that's being tested).

If you're simply wiring code together, extends is fine - when others are using your software, it's dangerous -- and you never know when it will switch from the former to the later.
14 years ago
if you're not going to post the code, but instead write that "I've done all of that but it's still not working" we can't help you.

It's fairly simple - one of your execution paths doesn't return a type of int.

We've narrowed this down to two possible places. Maybe remove the return errorMessage(blah, blah) and put in return 0;

also, after the closing curly brace for the if, put a return 0; - it should compile.
14 years ago
Not to be a forum nazi, but this probably belongs in the beginner forum.

As Fred has stated, each execution path (meaning each branch of every conditional) must resturn an int.

The problem is extremely simple, your convoluted code is making it difficult for you to understand.



[ December 13, 2007: Message edited by: Adam Schaible ]
14 years ago
You could look at it like dependency injection. We really aren't "injecting" it right now, but sure - we've setup the class to where it could easily be injected.

"Expose the interface not the class" can mean many different things - for example:



In the first example, we are referring to an implementation by it's interface - this would be considered good practice. One way to force the use of an interface is to provide a "factory" method that works like a constructor, but it's return type is the interface.



If someone wanted an instance of InterfaceExample, they have to use the getInstance() method, which returns it's interface.

Does that help?
14 years ago
That's exactly correct.

However, as you have seen in this thread, I am just a man with an opinion - and others may not see as much value in this solution as I do.

I should have made the returnWord() method private - it simply encapsulates the functionality better.
14 years ago
Actually, the template method doesn't depend on implementation inheritance.

Anything that can be achieved using implementation inheritance can be achieved with interfaces and composition - and you're left with a MUCH better design.

Your old abstract class is now concrete, and the "unimplemented" methods delegate to an interface that defines the old abstract methods.

So here's a simple example:



Problems with this: You've exposted your internal API - cannot have private and abstract. You really don't want people calling getWord, but you have no choice.

Also, you really can't change the AbstractProcessor much without having to change it's subclasses (or atleast test them).

Consider the following:



WordService is an interface that defines a method getWord();

I could list some other benefits, I just wanted to clarify that implementation inheritance isn't necessary to achieve the same functionality.
14 years ago

I have a Student class that sets up random student attributes



Post your Student class. From this code, you are trying to add the SAME student to the class several times.

The code might look something like:



Then you'd have to write a static method in the Student class to "randomly" generate the attributes of a student.

It's fairly trivial to do this, I'll give you some pointers after you post your Student code.
14 years ago
Go ahead and post your code, use [code] tags around it for readability.

There's no "built in" functionality to create random objects for you. You will have to either instantiate them as you have said, or write a service method to create "random" objects for you.
14 years ago