• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Ron McLeod
  • Rob Spoor
  • Tim Cooke
  • Junilu Lacar
Sheriffs:
  • Henry Wong
  • Liutauras Vilda
  • Jeanne Boyarsky
Saloon Keepers:
  • Jesse Silverman
  • Tim Holloway
  • Stephan van Hulst
  • Tim Moores
  • Carey Brown
Bartenders:
  • Al Hobbs
  • Mikalai Zaikin
  • Piet Souris

Best way to "delete" an object?

 
Ranch Hand
Posts: 84
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi All,
Suppose I have a class named User which keeps track of certain persistent properties (either in a property file, a database, or whatever). A User gets created via a createUser() method in the UserFactory class.
Further suppose that people using the User class want to delete users now and again. How is this best accomplished? It makes the most sense (to me at least) to implement a delete() method in the User class which will delete the user's associated files from the disk or the user's database entries. The problem is that the User object still exists! The person that deleted this user still has a perfectly valid reference to a User object, even though the delete() method has been called and the user's resources have been destroyed. What should happen when other methods get called on this user, such as getName(), getBirthday(), etc.? Should an IllegalStateException be thrown? Should they return null? It seems very kludgey to have to check every single method in User to see if delete() has previously been called, and then act accordingly.
It would be nice if delete() could set every reference to this object to null, but I suppose that's impossible. And there's no destructor (I'm not sure if having destructors would help here or not). Does anyone know of an elegant solution to this problem? Is the ugly one the only way?
Thanks,
Randy
 
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Randy Gordon:
What should happen when other methods get called on this user, such as getName(), getBirthday(), etc.? Should an IllegalStateException be thrown? Should they return null?


Hard to tell without knowing more about how the objects get used.
If it would be possible to return values so that the clients could work with them without knowing wether an object already was deleted, I would try that.
Otherwise I would give the clients a facility to ask the objects wether they are still valid (a query method) and throw an IllegalStateException if they are used when not in a valid state.

It seems very kludgey to have to check every single method in User to see if delete() has previously been called, and then act accordingly.
It would be nice if delete() could set every reference to this object to null, but I suppose that's impossible.


You could use the Proxy Pattern to imitate that functionality. Your clients would always get a proxy object which normally delegates all calls to the actual object. When the object gets deleted, you could set the reference encapsulated by the proxy to either null, or to a Null Object.
Does that help?
[ September 10, 2002: Message edited by: Ilja Preuss ]
 
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Randy,
Since you have a factory for creting User object , you can as well use the factory class for deleting the object.
It would be good if the User is identified with an ID (you can define a class UserID for that). Then you can track the User objects by ID and you can have a method in the Factory class like deleteUser(UserID id) that takes care of removing the User's associated data from the persistent medium.
Best Regards,
Ashoke Bhowmick

Originally posted by Randy Gordon:
Hi All,
Suppose I have a class named User which keeps track of certain persistent properties (either in a property file, a database, or whatever). A User gets created via a createUser() method in the UserFactory class.
Further suppose that people using the User class want to delete users now and again. How is this best accomplished? It makes the most sense (to me at least) to implement a delete() method in the User class which will delete the user's associated files from the disk or the user's database entries. The problem is that the User object still exists! The person that deleted this user still has a perfectly valid reference to a User object, even though the delete() method has been called and the user's resources have been destroyed. What should happen when other methods get called on this user, such as getName(), getBirthday(), etc.? Should an IllegalStateException be thrown? Should they return null? It seems very kludgey to have to check every single method in User to see if delete() has previously been called, and then act accordingly.
It would be nice if delete() could set every reference to this object to null, but I suppose that's impossible. And there's no destructor (I'm not sure if having destructors would help here or not). Does anyone know of an elegant solution to this problem? Is the ugly one the only way?
Thanks,
Randy

 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Ashoke Bhowmick:
It would be good if the User is identified with an ID (you can define a class UserID for that). Then you can track the User objects by ID and you can have a method in the Factory class like deleteUser(UserID id) that takes care of removing the User's associated data from the persistent medium.


How does that solve the problem of clients using User objects for already deleted records?
 
John Smith
Ranch Hand
Posts: 84
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ilja and Ashoke,
Thanks for the replies. Like Ilja remarked, having the factory object delete a User object doesn't really solve the problem of what to do when other methods are called on the User after it's been deleted. Furthermore, imagine I had dozens of factory classes (or hundreds). After an object is created, the client must forever remember that that factory is the one which must be used to delete the object. It seems simpler to just have the delete() method in the User class itself.


Hard to tell without knowing more about how the objects get used.
If it would be possible to return values so that the clients could work with them without knowing wether an object already was deleted, I would try that.


I want to treat methods that get called on a User after delete() has been called as programming errors, since it doesn't make any sense to do a getBirthday() or whatever if that information has been deleted from the machine. Thus, my initial thought was to check if the object has been deleted (and perhaps provide an isDeleted() method like you suggest) at the beginning of every method call in the User class. This just seems very inelegant to me, since I have to repeat that code (even if it's just one line) in every single method. There could be 50 for all I know (I haven't built the class yet). It seems like there's a pattern dying to get out here.
I took a look at the Proxy pattern, but as I understand it, I would have to subclass User and then override every method, delegating to the real User object if it hasn't been deleted yet, and throwing an exception if it has. Or, I could set the real User object to null after it has been deleted, and let the NullPointerException's take care of it for me, but that doesn't seem quite right. So I'm left with overriding every method in User (again, there could be many). This seems worse than just checking for deletion directly in the User class itself, since using a proxy would basically require me to, at the very least, duplicate every method signature as I wouldn't want any methods to get past the proxy without first checking whether or not the real User has been deleted.
So far, I'm leaning toward checking for deletion in every method inside the User class. If it's been deleted, it'll throw an IllegalStateException; otherwise, it'll procede normally. Does anyone have a better idea? Am I missing something fundamental about the Proxy pattern?
Thanks,
Randy
 
Ranch Hand
Posts: 1056
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
If you're using 1.4, and you consider accessing a deleted object to be a programming error, maybe an assertion is the answer?
assert !isDeleted();
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Ron Newman:
If you're using 1.4, and you consider accessing a deleted object to be a programming error, maybe an assertion is the answer?
assert !isDeleted();


That is a good idea.
Of course it doesn't solve the problem of not repeating that code over and over again...
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Randy Gordon:
So far, I'm leaning toward checking for deletion in every method inside the User class. If it's been deleted, it'll throw an IllegalStateException; otherwise, it'll procede normally. Does anyone have a better idea? Am I missing something fundamental about the Proxy pattern?


Two more ideas:
- if you are using JDK1.3 or later, you can make use of java.lang.reflect.Proxy, which is an implementation of the Dynamic Proxy pattern. The basic principle is that all method calls on the proxy get delegated to an InvocationHandler with a single method, which than could check wether the User already was deleted and use reflection to delegate to the actual User object if appropriate. It's a little bit more complex than the "normal" proxy, but you could avoid the duplication.
- if you don't mind using a pre-compiler, you could take a look at Aspect Oriented Programming (www.aspectj.org). Basically, an aspect is a bit of code that gets "woven into" a number of specified places (such as method declarations).
 
John Smith
Ranch Hand
Posts: 84
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ahh, very good. I'm using 1.4, so asserts are an excellent idea. I remember seeing something about InvocationHandler's when looking at the source for the Spin project, but completely forgot about it until Ilja mentioned it. That might be just what I'm looking for. Also, AspectJ looks promising, but I'm not sure I want to go there yet...
Randy
 
mister krabs
Posts: 13974
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
No! no! no! Asserts are a very bad idea. They should only be used as a development tool. Remember, asserts are by default turned off in production and there is no way to force asserts to be turned on. Read my article in this month's newsletter. Also there is no way to insure that a developer using your class will turn asserts on when they are developing. The Sun documentation states clearly, avoid asserts for pre-condition verification of public methods.
[ September 10, 2002: Message edited by: Thomas Paul ]
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Thomas Paul:
No! no! no! Asserts are a very bad idea. They should only be used as a development tool.


Well, to quote Randy:


I want to treat methods that get called on a User after delete() has been called as programming errors [...]


From that quote it seems to me that using assertions *might* be appropriate. But read on...

Remember, asserts are by default turned off in production and there is no way to force asserts to be turned on. [...] Also there is no way to insure that a developer using your class will turn asserts on when they are developing. The Sun documentation states clearly, avoid asserts for pre-condition verification of public methods.


I think that recommendation is slightly misleading. You certainly shouldn't use assertions for preconditions of *published* methods. As long as a method is only used by developers of your own team, it should be possible to ensure the activation of assertions for development by team resolution (if that isn't possible in your team, you have bigger problems than wether to use assertions, IMHO...).
 
John Smith
Ranch Hand
Posts: 84
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well, I agree that asserts shouldn't be used for pre-conditions on non-private methods, which I suppose is what we're talking about here. So, I'll stick with the exception throwing, even though calling a method after delete() has been called should never happen (i.e., it will always be programmer error).
 
Thomas Paul
mister krabs
Posts: 13974
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Ilja Preuss:
I think that recommendation is slightly misleading. You certainly shouldn't use assertions for preconditions of *published* methods.

Could you explain the difference between "public" and "published" methods?
And just wondering, are all your public classes always used only by your development team? Don't you share with other teams that may work for the same company but in a different division?
[ September 10, 2002: Message edited by: Thomas Paul ]
 
John Smith
Ranch Hand
Posts: 84
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yes, other teams could potentially work on these classes, so it's always good to bear that in mind. And we shouldn't forget about the people who have to maintain this stuff!
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Thomas Paul:
Could you explain the difference between "public" and "published" methods?


I could, but I think Martin Fowler can do that even better...

And just wondering, are all your public classes always used only by your development team?


No, some of them are published. The published part is marked with a custom javadoc tag.

Don't you share with other teams that may work for the same company but in a different division?


Yes, we are sharing specific libraries between teams. In a big company you might want to think of that code as "published". The company I am currently working for is not big enough that that would be necessary, IMO.
 
Thomas Paul
mister krabs
Posts: 13974
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Fowler seems to think that if you don't put it on the web then your interface is not a contract and you can do anything you like to it. He is quite wrong. Your public interface is your public contract and you should never change it once sent to production. Fowler seems to think that it is no big deal to force code changes in other programs. He is wrong. Every program that is changed must be retested and that could run into thousands of dollars of QA. Fowler seems to think that it is easy to use refactoring tools to find every line of code that your code change will effect. Again he is wrong unless you work in a small, single division shop that has no access to your code.
In any case, the Sun documentation says quite clearly that pre-condition testing of public methods should not be done with assertions. If you have a problem with that then I suggest you call Sun.
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Thomas Paul:
Fowler seems to think that if you don't put it on the web then your interface is not a contract and you can do anything you like to it.


I think the rest of the articel makes it rather obvious that "putting it on the web" was just meant as an example of not having full control over all clients of the interface and that he can imagine the necessity of shop-internal publishing:
"There is a limit to how big a team you can run without some form of internal publishing, but I would err on the side of too little publishing. In other words, assume you don�t need to publish interfaces, and then adjust if you find this causes problems."

Your public interface is your public contract and you should never change it once sent to production.


No, my *published* interface is my contract to external developers. For example, they don't get javadoc for public, non-published APIs.
And even Sun changes published interfaces - that is what they introduced the deprecation mechanism for.

Fowler seems to think that it is no big deal to force code changes in other programs. He is wrong. Every program that is changed must be retested and that could run into thousands of dollars of QA. Fowler seems to think that it is easy to use refactoring tools to find every line of code that your code change will effect. Again he is wrong unless you work in a small, single division shop that has no access to your code.


Sorry, I don't get your point. Fowler is exactly arguing that a public, unpublished API - that is, one over whichs usage you have full control - is easy to refactor, whereas a published API has to be much more rigid. That is the whole point of the differentiation, so it seems to me...

In any case, the Sun documentation says quite clearly that pre-condition testing of public methods should not be done with assertions. If you have a problem with that then I suggest you call Sun.


I don't have a problem with Sun saying that in their documentation. I hope you don't have a problem with me not agreeing with Sun in every point?
[ September 11, 2002: Message edited by: Ilja Preuss ]
 
You showed up just in time for the waffles! And this tiny ad:
Building a Better World in your Backyard by Paul Wheaton and Shawn Klassen-Koop
https://coderanch.com/wiki/718759/books/Building-World-Backyard-Paul-Wheaton
reply
    Bookmark Topic Watch Topic
  • New Topic