wood burning stoves*
The moose likes Beginning Java and the fly likes Returning Unique Objects from Methods Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Android Security Essentials Live Lessons this week in the Android forum!
JavaRanch » Java Forums » Java » Beginning Java
Bookmark "Returning Unique Objects from Methods" Watch "Returning Unique Objects from Methods" New topic
Author

Returning Unique Objects from Methods

Stevens Miller
Ranch Hand

Joined: Jul 26, 2012
Posts: 523
    
    3

I need to prompt the user for the name of a new document, with the option to cancel creation of the new document. One way to do that might look like this:


(The above ignores issues regarding clobbering existing files; that's okay for the purposes of my question.)

Now, some documents need parameters set for them before I can open them. For example, a document might be a three-dimensional space for a machine part. In those cases, I want to call a method that will query for those parameters, and pass the returned object to the creation method:



Of course, the user might want to cancel this transaction at the point where they are being prompted to enter parameters, so let's have that method return null in that case. We might do this:



However, this means that if the user cancels at the point where they have entered the parameters, and is being asked for the document name, they will be exited from the entire method. What I would prefer is that they be returned to the parameter-input stage, like this:



Now here's where it gets more complicated. Suppose the above is part of a generic system that is intended to create documents that have parameters and also to create documents that don't have parameters. Those that don't have them must still have some kind of "getParameters()" method. A default method could return a value that is never used, but we do need to test for it so we don't loop endlessly upon cancelation at the naming stage. That could work like this:



In this case, all calls to "getParameters()" return Parameters.NO_PARAMETERS immediately, which allows cancelation at the naming stage (that is, within "showOpenDialog()") to exit the loop.

Now, where does Parameters.NO_PARAMETERS get defined? I had thought this would be a good idea, inside the Parameters class file:

However, for guidance, I looked into the source code for JOptionPane, which has, as one of its public fields, UNINITIALIZED_OBJECT. In that source code, to my surprise, I found this:

The reason I am surprised is that, as I understand it, compile-time strings are all kept in a pool that makes sure no space is wasted by storing the same immutable string as two separate instances of a String object. While each use of "new Object()" returns a unique instance, all appearances of "uninitializedValue" would return the same instance. While it may be unlikely that any user-written "getParameters()" method would return, as its parameters, an object that was actually a refrence to a String containing the compile-time object "noParameters", one could not absolutely rule that out. (I don't know if the problem exists for JOptionPane, as any subclass thereof may not be able to return its own string in place of JOptionPane.UNINITIALIZED_VALUE, but it might; have to check.)

So, here's my question: when a method might return a new instance of some class, but might also return objects that are to be interpreted specially (such as those that represent cancelation of the transaction, or those that indicate the method never allows cancelation), is it safer to have those unique objects created at run time by "new Object()" as opposed to creating them at compile time, the way it is done in JOptionPane?
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Stevens Miller wrote:So, here's my question: when a method might return a new instance of some class, but might also return objects that are to be interpreted specially (such as those that represent cancelation of the transaction, or those that indicate the method never allows cancelation), is it safer to have those unique objects created at run time by "new Object()" as opposed to creating them at compile time, the way it is done in JOptionPane?


First, all objects are created at runtime. None at compile-time.

So your question boils down to, "Is it safe to create separate objects to represent this 'special value', or to cache a single value?" The answer is: It depends.

If that special value is immutable, then it's safe to just share it. If it's mutable (which wouldn't make sense for any use case that I can think of), then you'd have to create separate instances.

For your case, it sounds like either


or


would be fine. But note that since it's a static variable, only one will ever be created anyway.

Mike Simmons
Ranch Hand

Joined: Mar 05, 2008
Posts: 2996
    
    9
[replying to Stevens, independent of Jeff's reply above]

Of those two choices, I would pick the "new Object()" as safer, for the reasons you cite. However, I would recommend something else - don't return an Object, but instead a Parameter instance which represents the concept of an uninitialized parameter. This instance could also have a toString() method that returns a meaningful string, e.g. "Parameter[uninitialized]" or something. This is more type-safe and useful in debugging, especially for someone not familiar with the internal implementation of your Parameter class. If they just see an Object, they have no idea what that means. If they see Parameter[uninitialized], they have a much better chance at understanding what's going on.
Stevens Miller
Ranch Hand

Joined: Jul 26, 2012
Posts: 523
    
    3

Jeff Verdegan wrote:First, all objects are created at runtime. None at compile-time.

Ah, thanks. The distinction I guess I should have made was between Strings defined at compile-time and those defined at run-time.
For your case, it sounds like either


or


would be fine. But note that since it's a static variable, only one will ever be created anyway.


Perhaps I am misunderstanding your point, but I don't think that addresses the dilemma I'm asking about. The issue I see is that (however unlikely this may be), a user's override method for getParameters() might return "this is my dummy 'no parameters' object", with the intent that this actually be the parameters returned, rather than an indication that no parameters are returned by this method (and, therefore, that it will also never give the user a chance to choose "cancel" when it is called). If such an override did that, the caller wouldn't know that the returned object was actually intended to contain parameters, as opposed to indicating that no parameters are returned. As far-fetched as that sounds, suppose the override looked like this:

If the user were to type in, "this is my dummy 'no parameters' object" and subsequently tested for "== Parameters.NO_PARAMETERS", that test would evaluate to true.

Put rather more in isolation, when one writes:

then this will always evaluate to true:

Whereas, when one writes:

then this will always evaluate to false:


Assuming that one wants to be utterly sure that Parameters.NO_PARAMETERS never evaluates to true for Parameters.NO_PARAMETERS == <any other object variable> (unless that other object variable can have its value traced back to Parameters.NO_PARAMETERS), I'm wondering why the writers of JOptionPane used the hard-coded String and not new Object().
Stevens Miller
Ranch Hand

Joined: Jul 26, 2012
Posts: 523
    
    3

Mike Simmons wrote:However, I would recommend something else - don't return an Object, but instead a Parameter instance which represents the concept of an uninitialized parameter. This instance could also have a toString() method that returns a meaningful string, e.g. "Parameter[uninitialized]" or something. This is more type-safe and useful in debugging, especially for someone not familiar with the internal implementation of your Parameter class. If they just see an Object, they have no idea what that means. If they see Parameter[uninitialized], they have a much better chance at understanding what's going on.


How about something like this?


Callers could test for

and there's no risk that any other object variable is going to contain a reference to the same object referenced by NO_PARAMETERS, even if the user overrides getParameters() and it returns new String("No parameters"). And, calling Parameters.NO_PARAMETERS.toString() returns "No parameters", just like you want.

The NetBeans IDE chides me for using the String constructor, but I don't see any other way to be sure I have a unique object reference to a String.

What do you think of that approach?
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Stevens Miller wrote:Perhaps I am misunderstanding your point, but I don't think that addresses the dilemma I'm asking about. The issue I see is that (however unlikely this may be), a user's override method for getParameters() might return "this is my dummy 'no parameters' object", with the intent that this actually be the parameters returned, rather than an indication that no parameters are returned by this method


Okay, I see what you're getting at now. Then, yes, if you want to ensure a unique object that can never be == to or equals() to any other object (unless somebody deliberately defines and incorrect equals() method), then new Object(), or some instance of your own class or enum is the way to go.

Is Parameter your class or part of the core API? If yours, you can make a special instance that's never equal to any other instance. If it's part of the core API, you'd have to look at its rules for equals().
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Stevens Miller wrote:es me for using the String constructor, but I don't see any other way to be sure I have a unique object reference to a String.


The very thing it's chiding you about there can actually work to your advantage, depending on whether you need a unique object (it helps you), or the more strict requirement that it's not equals() to any other object (it doesn't help you).

Frankly I wouldn't rely on needing just == being false, rather than equals() as well. I'd do either new Object() or some Parameter instance that can never be equals() to anything else.
Stevens Miller
Ranch Hand

Joined: Jul 26, 2012
Posts: 523
    
    3

Jeff Verdegan wrote:Okay, I see what you're getting at now. Then, yes, if you want to ensure a unique object that can never be == to or equals() to any other object (unless somebody deliberately defines and incorrect equals() method), then new Object(), or some instance of your own class or enum is the way to go.

Yes, we're on the same page.

Is Parameter your class or part of the core API? If yours, you can make a special instance that's never equal to any other instance. If it's part of the core API, you'd have to look at its rules for equals().

It's my own class (well, in my program it's called something rather more likely to be unique; I picked "Parameters" for this posting).

I considered an enum, but I can't claim I'm as skilled with those yet as I feel I should be to use them for this purpose. That's what got me into looking at the JOptionPane source. I figured that would be a good example to follow. But, I was really expecting to see "new Object()" in there (or something like it). When I saw the hard-coded String, some dusty neuron fired and reminded me that Java tries not to create distinct String objects.

Since I don't think of myself as better at Java than the people who wrote it (or, for the most part, the people who wrote JOptionPane), I'm mostly here asking if there is some reason why they did it with a hard-coded String and not a "new String()" or some other way.

(For my purposes, protecting against spurious "==" true results will do, but you make a good point about equals(). I'll try to keep that in mind.)
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Stevens Miller wrote:That's what got me into looking at the JOptionPane source. I figured that would be a good example to follow. But, I was really expecting to see "new Object()" in there (or something like it). When I saw the hard-coded String, some dusty neuron fired and reminded me that Java tries not to create distinct String objects.


I agree that what you found in JOptionPane is not a good approach, although I don't know the entire context, so I might be missing something. There's a good chance it was put there as a quick, simple, "unique" value when the class was introduced 15 years ago or so, and never given a second glance since.
Mike Simmons
Ranch Hand

Joined: Mar 05, 2008
Posts: 2996
    
    9
The writers of JOptionPane were part of a large group of people putting out a large amount of code in a relatively small amount of time, at a time when many Java idioms were still evolving. Sometimes they did strange things. For the choice they made here, the only advantage I see is that it does at least have a meaningful toString() representation, more so than new Object(). But as we've seen, there can be better ways to achieve that. I'm guessing these alternatives simply didn't occur to whoever was writing the class. Or they figured no one would have any incentive to create another parameter with the exact same string literal.

The new String("No parameters") technique is indeed an improvement over what they did, in my opinion. However I'd still prefer to see a separate Parameter value returned. Does getParameters() normally return some random Object? How do you use that, in general? It's a bit hard to imagine how that API works. For that matter your getParameters() will not work as shown, since you're casting a String to be a Parameter, which it isn't. Also, youre using a String in a nonstandard way, expecting people to test against it using == rather than equals(), and that's against the grain for many Java programmers, contrary to the usual advice. Even if it works just fine in this case, you have to spend more time convincing others it's OK. Typically, that's not worth the trouble unless you've got a good reason.

I'm thinking of something more like:

Of course if you develop Parameters further, you may have a more general toString() implementation for that class, and you may not need to make an anonymous subclass as I did above.

Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Mike Simmons wrote:However I'd still prefer to see a separate Parameter value returned.


Agreed. If Parameter has some arbitrary "value" or somesuch field, then something like this should do:


Or one could define a subclass of Parameter, possibly anonymous, that is only ever instantiated once, and that is never equal to any other Parameter.

There are multiple options, and which one is most suitable depends on the constraints of the specific situation.
Mike Simmons
Ranch Hand

Joined: Mar 05, 2008
Posts: 2996
    
    9
Jeff Verdegan wrote:Or one could define a subclass of Parameter, possibly anonymous, that is only ever instantiated once, and that is never equal to any other Parameter.

Kind of like, say, the one I just showed. (Assuming no one adds a new equals() method that screws things up.)

Jeff Verdegan wrote:There are multiple options, and which one is most suitable depends on the constraints of the specific situation.

Agreed. I think we're mostly missing any info on what the Parameters class is supposed to do when it has been initialized. Design that, and I'm sure we can find a way to implement the Null Object Pattern within that framework.

Another approach is to replace Parameters with a Map<String, String>. A bunch of key-value pairs for whatever parameters you want to define, which is very flexible. Then NO_PARAMETERS would simply be an empty Map:
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Mike Simmons wrote:
Jeff Verdegan wrote:Or one could define a subclass of Parameter, possibly anonymous, that is only ever instantiated once, and that is never equal to any other Parameter.

Kind of like, say, the one I just showed.


Er, um, yup. That.

++ on the rest of what you said as well. The Null Object Pattern popped into my head when I first read the thread, and then of course I promptly forgot to mention it.
Stevens Miller
Ranch Hand

Joined: Jul 26, 2012
Posts: 523
    
    3

My apologies for not responding to these last few comments sooner. For some reason, I wasn't able to access coderanch.com for two days.

Great advice! I don't think the null object pattern is warranted in this case, as the only objects that should pass on to code that would need it are those that do not equate to "no parameters." Further, though unlikely, I may actually need to pass a bona fide null object, rather than interpret it as meaning that the user is being asked for any parameters (I can see that calling my "special" object "NO_PARAMETERS" is ambiguous in that regard).

This has been a terrific set of answers to my initial query. Thanks muchly!

(Marking this thread resolved.)
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Stevens Miller wrote:I don't think the null object pattern is warranted in this case, as the only objects that should pass on to code that would need it are those that do not equate to "no parameters."


You wouldn't necessarily have to use it to represent null per se. It's just the general pattern of a special object meant to indicate a particular value outside the normal range of possible "real" values.

Further, though unlikely, I may actually need to pass a bona fide null object
,

There is no such thing. Only references can be null in Java, not objects.
Stevens Miller
Ranch Hand

Joined: Jul 26, 2012
Posts: 523
    
    3

Jeff Verdegan wrote:
Stevens Miller wrote:I don't think the null object pattern is warranted in this case, as the only objects that should pass on to code that would need it are those that do not equate to "no parameters."


You wouldn't necessarily have to use it to represent null per se. It's just the general pattern of a special object meant to indicate a particular value outside the normal range of possible "real" values.

Further, though unlikely, I may actually need to pass a bona fide null object
,

There is no such thing. Only references can be null in Java, not objects.


Hmmm... I think we're using our terms differently from each other. I meant "null object" in the sense of the Wikipedia item linked to above. As I understood that item, a null object actually does implement the methods of a class, but none of them do anything. That's not the same as having a specific reference stand for a return value that is distinct from anything in the normal range of "real" values. Here, I actually need such a special object meant to indicate a particular value. It need not be a null object (again, in the sense of the null object pattern), because I know it will never be called upon to supply the interface defined for any class (which genuine null objects must do). Like I said, although it is not likely, my parameter values might actually be represented by a null object, which means it couldn't be used to represent a special value.
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Stevens Miller wrote:Hmmm... I think we're using our terms differently from each other. I meant "null object" in the sense of the Wikipedia item linked to above. As I understood that item, a null object actually does implement the methods of a class, but none of them do anything.


Ah, okay, so still talking about the "null object pattern" then. Sorry for any confusion. A very common mistake made by beginners, and even by people with a moderate amount of experience, is to think about objects being null--null in the sense of the Java language meaning of the word, like someObj = null. This misconception usually comes from not being aware of the distinctions among objects, references, and variables.

Anyway, I guess I saw the words "null object" and thought that's what you were talking about, and I wanted to disabuse you of that notion post-haste.
Stevens Miller
Ranch Hand

Joined: Jul 26, 2012
Posts: 523
    
    3

Jeff Verdegan wrote:A very common mistake made by beginners, and even by people with a moderate amount of experience, is to think about objects being null--null in the sense of the Java language meaning of the word, like someObj = null. This misconception usually comes from not being aware of the distinctions among objects, references, and variables.

Yup, an important distinction you've got there. When I discuss my code with my wife (who is also a programmer, though mostly VB6), I never say that a variable "is a SuchAndSuch object." I try always to say something like, "it contains a reference to a SuchAndSuch object." It's a subtle distinction, but it implicates rather a lot and helps keep one's thinking clear about what certain bits of code a really doing.

For example, something as mundane as "Object SuchAndSuch sasObject = sasOtherObject" has very low run-time overhead, because it only copies a reference. I'm aware that some beginners initially think this is a costly thing because they (mistakenly) believe it copies an object. By always discussing the contents of variables in terms of references, one never loses sight of the fact that the objects themselves are not stored in the variables used to access and operate on them.
 
It is sorta covered in the JavaRanch Style Guide.
 
subject: Returning Unique Objects from Methods
 
Similar Threads
Working out a problem statement posted in another thread.
ArrayList storing only last table record
var args problem
dynamically rerender datatable content from managedbean?
Why do we need semaphore?