help me understand generics

  • Thread starter Maqsood Mohammed
  • Start date
M

Maqsood Mohammed

Hi there,
I'm new to java generics, and to further understand i wrote a simple
program.. but i think i either got my interface wrong or perhaps dont'
fully understand when to parametrize interfaces.

consider,

interface Dryable<T> {
boolean dry(T obj);
}

interface Washable<T> {
boolean wash(T obj);
}

interface Dryer<T extends Dryable<T>> {
T dryIt(T obj); // return "dried" obj
};

interface Washer<T extends Washable<T>> {
T washIt(T obj); // return "washed" obj
}

// TODO: later change, to accept a list of items..
interface DryerWasher<T extends Washable<T> & Dryable<T>> extends
Dryer<T>, Washer<T> {
boolean cleanIt(T obj);
}


class Apparel implements Washable<Apparel>, Dryable<Apparel> {
String description;
Apparel(String description){
this.description = description;
}
public String toString(){
return description;
}

public boolean wash(Apparel obj){
System.out.println("washing apparel:"+obj);
return true;
}

public boolean dry(Apparel obj){
System.out.println("drying apparel:"+obj);
return true;
}
}

class ApparelDryerWasher implements DryerWasher<Apparel> {
public boolean cleanIt(Apparel obj) {
System.out.println("starting washing");
Apparel w_obj = washIt(obj);
System.out.println("starting drying");
Apparel wd_obj = dryIt(w_obj);
System.out.println("done");
}

public Apparel dryIt(Apparel obj) {
return obj.dry(this);
}
public Apparel washIt(Apparel obj){
return obj.wash(this);
}
}


public static void main(String[] args) {

ApparelDryerWasher apparelCleaner = new ApparelDryerWasher();
apparelCleaner.cleanIt(new Apparel("Jeans-A"));
apparelCleaner.cleanIt(new Apparel("Jeans-B"));
}




Rightaway a compilation-error, stating that ApparelDryerWasher.dry
cannot be applied to ApparelDryerWasher parameter, i understand
passing DryerWasher to "dry" is outrageous, but saying obj.dry() would
mean Dryable interface cannot be parametrized..should it be?

There are plenty things wrong with my design, I'd like to hear what
are the various ways to design/implement this solution..

Thanks,
 
M

Mark Space

Maqsood said:
Rightaway a compilation-error, stating that ApparelDryerWasher.dry
cannot be applied to ApparelDryerWasher parameter, i understand
passing DryerWasher to "dry" is outrageous, but saying obj.dry() would
mean Dryable interface cannot be parametrized..should it be?

There are plenty things wrong with my design, I'd like to hear what
are the various ways to design/implement this solution..


The only error I'm seeing is:

public Apparel dryIt( Apparel obj )
{
return obj.dry( this );
}

"dryIt" says it returns an Apparel, but dry() returns a boolean. Similar
or washIt. Is that what you are talking about?

I'm not sure what you are trying to do with your design, so it's kind of
hard for me to propose a solution.
 
M

Mac

The only error I'm seeing is:

     public Apparel dryIt( Apparel obj )
     {
         return obj.dry( this );
     }

"dryIt" says it returns an Apparel, but dry() returns a boolean. Similar
or washIt. Is that what you are talking about?

I'm not sure what you are trying to do with your design, so it's kind of
hard for me to propose a solution.

Thanks for pointing that out.. Let me correct it first, and then i'll
bring up what i'd in mind when i started this program..


interface Dryable<T> {
boolean dry(T obj); // successfully dried or not?
}

interface Washable<T> {
boolean wash(T obj); // successfully washed or not?
}

interface Dryer<T extends Dryable<T>> {
void dryIt(List<T> obj);
};

interface Washer<T extends Washable<T>> {
void washIt(List<T> obj);
}


interface DryerWasher<T extends Washable<T> & Dryable<T>>
extends
Dryer<T>, Washer<T> {
boolean cleanIt(List<T> obj); // does both drying and
washing.
}

class Apparel implements Washable<Apparel>, Dryable<Apparel> {
String description;
Apparel(String description){
this.description = description;
}
public String toString(){
return description;
}

public boolean wash(Apparel obj){
System.out.println("washing apparel:"+obj);
return true;
}

public boolean dry(Apparel obj){
System.out.println("drying apparel:"+obj);
return true;
}
}

class ApparelDryerWasher implements DryerWasher<Apparel> {

public boolean cleanIt(List<Apparel> objs) {
System.out.println("starting washing");
washIt(objs);
System.out.println("starting drying");
dryIt(objs);
System.out.println("done");
}

void dryIt(List<Apparel> objs){
for (Apparel obj: objs) {
obj.dry(this);
}
}

void washIt(List<Apparel> objs){
for (Apparel obj: objs) {
obj.wash(this);
}
}

}

public static void main(String[] args) {

ApparelDryerWasher apparelCleaner = new
ApparelDryerWasher();
Apparel[] apparels = new Apparel[] { new Apparel
("Jeans-A"), new Apparel("Jeans-B")};
apparelCleaner.cleanIt(Arrays.asList(apparels));
}

Lets say we've a similar DryerWasher class for Utensils, call it,
UtensilDryerWasher.

Now, i've a this crazy idea of creating a UniversalDryerWasher which
can wash either utensils, apparel or both.
How would i implement that class, would type param T of DryerWasher
interface be an ancestor of both Apparel and Utensil class, that
seems' Yuck, I dont' think so, since both Apparel and Utensil are both
dryable/washable. But i can't think off a better way.

Any ideas?
 
T

Tom Anderson

interface Dryable<T> {
boolean dry(T obj); // successfully dried or not?
}

interface Washable<T> {
boolean wash(T obj); // successfully washed or not?
}

Why do the methods take parameters? Is the parameter the thing to be
washed/dried? In which case, what's the object on which the method will be
called? Shouldn't it be:

interface Dryable {
boolean dry();
}

Then you do:

Dryable soggy = new Apparel();
soggy.dry();

?

If so, then neither Dryable nor Washable need to be generic themselves.
They can just be normal interfaces.
interface Dryer<T extends Dryable<T>> {
void dryIt(List<T> obj);
};

interface Washer<T extends Washable<T>> {
void washIt(List<T> obj);
}
Okay.

interface DryerWasher<T extends Washable<T> & Dryable<T>> extends Dryer<T>, Washer<T> {
boolean cleanIt(List<T> obj); // does both drying and washing.
}
Okay.

class Apparel implements Washable<Apparel>, Dryable<Apparel> {
String description;
Apparel(String description){
this.description = description;
}
public String toString(){
return description;
}

public boolean wash(Apparel obj){
System.out.println("washing apparel:"+obj);
return true;
}

public boolean dry(Apparel obj){
System.out.println("drying apparel:"+obj);
return true;
}
}

This brings me back to the meaning of the parameter to wash/dry - are you
saying that one item of apparel can wash or dry another? What does this:

new Apparel("sock").wash(new Apparel("shirt"));

mean?
class ApparelDryerWasher implements DryerWasher<Apparel> {

public boolean cleanIt(List<Apparel> objs) {
System.out.println("starting washing");
washIt(objs);
System.out.println("starting drying");
dryIt(objs);
System.out.println("done");
}

void dryIt(List<Apparel> objs){
for (Apparel obj: objs) {
obj.dry(this);
}
}

obj.dry(this)? That won't compile. Do you mean obj.dry(obj)?
void washIt(List<Apparel> objs){
for (Apparel obj: objs) {
obj.wash(this);
}
}

Same again here.
}

public static void main(String[] args) {

ApparelDryerWasher apparelCleaner = new ApparelDryerWasher();
Apparel[] apparels = new Apparel[] { new Apparel ("Jeans-A"), new Apparel("Jeans-B")};
apparelCleaner.cleanIt(Arrays.asList(apparels));
}
Okay.

Lets say we've a similar DryerWasher class for Utensils, call it,
UtensilDryerWasher.
Okay.

Now, i've a this crazy idea of creating a UniversalDryerWasher which
can wash either utensils, apparel or both.

Okay. Not sure if that's really practical, but let's roll with it.
How would i implement that class, would type param T of DryerWasher
interface be an ancestor of both Apparel and Utensil class, that seems'
Yuck, I dont' think so, since both Apparel and Utensil are both
dryable/washable. But i can't think off a better way.

You could write it as a generic class, that could clean anything that was
both washable and dryable. Like this:

class UniversalDryerWasher<T extends Washable & Dryable> implements DryerWasher<T> {
public boolean cleanIt(List<T> objs) {
// etc
}
}

But (a) that wouldn't be restricted to Apparels and Utensils and (b) any
one instance of it could only clean either Apparels or Utensils.

I don't believe there's any way to write a class such that it would only
clean Apparel or Utensil objects, and not other Washable and Dryable
classes. Without that, there's no way to have a single instance that would
do both either.

As you say, you could introduce a new type:

interface DomesticCleanable extends Washable, Dryable

And then make Apparel and Utensil implement that. You could then write a
UniversalDryerWasher class which would handle anything which was a
DomesticCleanable.

tom
 
M

Mac

Why do the methods take parameters? Is the parameter the thing to be
washed/dried? In which case, what's the object on which the method will be
called? Shouldn't it be:

interface Dryable {
        boolean dry();

}

Then you do:

Dryable soggy = new Apparel();
soggy.dry();

?

If so, then neither Dryable nor Washable need to be generic themselves.
They can just be normal interfaces.

You are right, I'd not thought about it, I guess, i was too eager to
use generic type-param.
This brings me back to the meaning of the parameter to wash/dry - are you
saying that one item of apparel can wash or dry another? What does this:

new Apparel("sock").wash(new Apparel("shirt"));

mean?

Yes, That seems wrong, but i intended it to be used as

dryerWasher.wash(new Apparel("shirt"))
       class ApparelDryerWasher implements DryerWasher<Apparel> {
               public boolean cleanIt(List<Apparel> objs) {
                       System.out.println("starting washing");
                       washIt(objs);
                       System.out.println("starting drying");
                       dryIt(objs);
                       System.out.println("done");
               }
              void dryIt(List<Apparel> objs){
                   for (Apparel obj: objs) {
                     obj.dry(this);
                   }
              }

obj.dry(this)? That won't compile. Do you mean obj.dry(obj)?
              void washIt(List<Apparel> objs){
                   for (Apparel obj: objs) {
                       obj.wash(this);
                   }
              }

Same again here.
       }
   public static void main(String[] args) {
               ApparelDryerWasher apparelCleaner = new ApparelDryerWasher();
               Apparel[] apparels = new Apparel[] { new Apparel ("Jeans-A"), new Apparel("Jeans-B")};
               apparelCleaner.cleanIt(Arrays.asList(apparels));
   }
Okay.

Lets say we've a similar DryerWasher class for Utensils, call it,
UtensilDryerWasher.
Okay.

Now, i've a this crazy idea of creating a UniversalDryerWasher which
can wash either utensils, apparel or both.

Okay. Not sure if that's really practical, but let's roll with it.
How would i implement that class, would type param T of DryerWasher
interface be an ancestor of both Apparel and Utensil class, that seems'
Yuck, I dont' think so, since both Apparel and Utensil are both
dryable/washable. But i can't think off a better way.

You could write it as a generic class, that could clean anything that was
both washable and dryable. Like this:

class UniversalDryerWasher<T extends Washable & Dryable> implements DryerWasher<T> {
        public boolean cleanIt(List<T> objs) {
                // etc
        }

}

What is the declaration for DryerWasher in this case? shouldn't we be
placing bounds on the type-param of DryerWasher interface instead?

interface DryerWasher<T extends Washable & Dryable> extends
Dryer, Washer {
// cleanIt
}

class UniversalDryerWasher implements DryerWasher<????> { //
hmm...not sure what the type-argument should be now.
}

Please clarify.
 
M

Mark Space

I was struck by your comment to Tom that you were "over-eager to use
generics" because I was already thinking the same thing.

Let me try to explain. You say (addressed below) that your goal is to
create a universal dryer-washer. But you're trying to do this with
generics, which to me is contrary.

Generics specialize classes by parameterizing the class. Generics don't
make classes universal, generics make classes specific.

For example, from the Java API, the class Enum is declared like this:

Enum <E extends Enum<E>> {...}

This seems syntactically similar to what you are doing. So what does
this do for the Enum class? Well, it makes it so you can't pass every
type of enum to methods parameterized this way. For example:

class Months extends Enum<Months> {...}
class Animals extends Enum<Animals> {...}

This is a syntax error because Enum is final, but this is what you end
up with when you make an enumeration. So Enum also contains a method
compareTo:

public int compareTo( E e ) {...}

What this E here does is make it so you can only compare Months to other
Months, and Animals to other Animals.

JANUARY.compareTo( MARCH );

for example. You could not compare JANUARY to an animal, because the
type of the bound (E) is "Months" and DOG is not a month.

JANUARY.compareTO( DOG ); // fails
CAT.compareTo( DOG ); // OK

So that's what this type of recursive bound is for, it specializes the
class Enum so that it can only be uses with one type of child class.

Lets say we've a similar DryerWasher class for Utensils, call it,
UtensilDryerWasher.

Now, i've a this crazy idea of creating a UniversalDryerWasher which
can wash either utensils, apparel or both.

However, if you want to make a method that takes ANY type of Enum, the
trick is just to not use generics or type parameterization.

findNextEnumeration( Enum<?> e );

That's it. You can now pass any type of enum here, Months or Animals,
because the base class is used as the type, not a generic. So in the
same way, if you want to create a universal DryerWasher, just use the
base class as a method parameter without generics.

class UniversalDryerWasher {
public boolean dryIt( Dryable<?> d ) {...}
public boolean washIt( Washable<?> w ) {...}
}


The problem you are running into with the structure you have is it's
designed to prevent universalities like this, just like Enum is designed
to prevent you from accidentally comparing Animals to Months.
 
T

Tom Anderson

What is the declaration for DryerWasher in this case? shouldn't we be
placing bounds on the type-param of DryerWasher interface instead?

interface DryerWasher<T extends Washable & Dryable> extends Dryer, Washer {
// cleanIt
}

class UniversalDryerWasher implements DryerWasher<????> { // hmm...not sure what the type-argument should be now.
}

Please clarify.

You do need the bound on DryerWasher. But i think (i *think* - i haven't
tried compiling this) that you need to repeat the bound on
UniversalDryerWasher - you can't just call it a UniversalDryerWasher<T>.
And if you want to clean both clothes and utensils, there's no more
specific type than T extends Washable & Dryable that you can put in the
bound.

tom
 
R

Roedy Green

There are plenty things wrong with my design, I'd like to hear what
are the various ways to design/implement this solution..

for a start see http://mindprod.com/jgloss/generics.html

In is an informal introduction to generics that several emails have
told me helped people get started. It is not a complete essay, more
of a cookbook to help you get started and do the most common things
with generics.
--
Roedy Green Canadian Mind Products
http://mindprod.com

"Learning is not compulsory... neither is survival."
~ Dr. W. (William) Edwards Deming (born: 1900-10-14 died: 1993-12-20 at age: 93))
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top