abstract classes and generic types

H

horos11

All,

I'm trying to overcome the following problem. I'd like to have an
abstract class contain common functionality for subclasses, but I
don't want to be limited by the representations of them. For example:

abstract class a
{
String calculate() { return this.put(this.my_func()); }
}

class b extends a
{
Set<Integer> myset;

Integer my_func() { return (1); }
void put(Integer myint) { myset.put(myint); }
}

class c extends a
{
Set<Float> myset;
Float my_func() { return(1.0); }
void put(Float myfloat) { myset.put(myfloat); }
}

As it stands, if I put the return types, etc. in the abstract class it
gets exceedingly ugly because implementation details are seeping into
the abstract class and it would need to be updated with new function
signatures each time a new subclass is created. I need to find a way
to say that any given method is *purely* abstract, ie: that it will be
defined solely in the subclass.

Is there a way to do this, or am I pretty much stuck reimplementing
lots of functionality in each subclass?

thanks much..
 
D

Donkey Hottie

(e-mail address removed) wrote in (e-mail address removed):
All,

I'm trying to overcome the following problem. I'd like to have an
abstract class contain common functionality for subclasses, but I
don't want to be limited by the representations of them. For example:

abstract class a
{
String calculate() { return this.put(this.my_func()); }
}

class b extends a
{
Set<Integer> myset;

Integer my_func() { return (1); }
void put(Integer myint) { myset.put(myint); }
}

class c extends a
{
Set<Float> myset;
Float my_func() { return(1.0); }
void put(Float myfloat) { myset.put(myfloat); }
}

As it stands, if I put the return types, etc. in the abstract class it
gets exceedingly ugly because implementation details are seeping into
the abstract class and it would need to be updated with new function
signatures each time a new subclass is created. I need to find a way
to say that any given method is *purely* abstract, ie: that it will be
defined solely in the subclass.

Is there a way to do this, or am I pretty much stuck reimplementing
lots of functionality in each subclass?

thanks much..

abstract class a
{
protected Set<Object> myset = new java.util.HashSet<Object>();

// how put returns a String is beyond me ???
String calculate() { this.put(this.myfunc()); return "barf"; }

abstract Object my_func() ;
}

class b extends a
{
@Override
Object my_func() { return new Integer(1); }

void put(Integer myint) { myset.put(myint); }
}

class b extends a
{
@Override
Object my_func() { return new Float(1); }

void put(Float myfloat) { myset.put(myfloat); }
}
 
D

Donkey Hottie

(e-mail address removed) wrote in (e-mail address removed):


abstract class a
{
protected Set<Object> myset = new java.util.HashSet<Object>();

// how put returns a String is beyond me ???
String calculate() { this.put(this.myfunc()); return "barf"; }

abstract Object my_func() ;
}

class b extends a
{
@Override
Object my_func() { return new Integer(1); }

void put(Integer myint) { myset.put(myint); }
}

class b extends a
{
@Override
Object my_func() { return new Float(1); }

void put(Float myfloat) { myset.put(myfloat); }
}

I cancelled this. It has no point, the original sample is beyond any clue
and no point in refining it.

Sorry.
 
G

Giovanni Azua

How about:

public abstract class A<N extends Number> {
void calculate() { put(my_func()); }
abstract N my_func();
void put(N myN) { set.add(myN); }
private final Set<N> set = new HashSet<N>();
}

public class B extends A<Long> {
@Override
Long my_func() { return Long.valueOf(1); }
}

AFAIK you can't do A generic without ressorting to reflection to get hold of
the right constructor for the Number subclass.

HTH,
regards,
Giovanni
 
G

Giovanni Azua

Donkey Hottie said:
I cancelled this. It has no point, the original sample is beyond any clue
and no point in refining it.
:) yes but some alternatives for the OP to get an idea would be helpful I
think.

I tried to address his question:
"I need to find a way to say that any given method is *purely* abstract"

Best regards,
Giovanni
 
L

Lew

Class names should begin with an upper-case letter, and comprise compound word
parts, each subsequent part also beginning with an upper-case letter. This
mixed-case convention is called "camel case". Thus, the class name should be "A".

Method and variable names other than of constants should begin with a
lower-case letter and thereafter be in camel case. Underscores should not be
in such names. Thus, "myFunc()" (although "Func" in a function name is
redundant and useless).

'class B extends A'

'mySet' (although "Set" in the name of a set is actually silly and somewhat
harmful to refactoring).
Integer my_func() { return (1); }
void put(Integer myint) { myset.put(myint); }
}

class c extends a
{
Set<Float> myset;
Float my_func() { return(1.0); }
void put(Float myfloat) { myset.put(myfloat); }
}

As it stands, if I put the return types, etc. [sic] in the abstract class it
gets exceedingly ugly because implementation details are seeping into
the abstract class and it would need to be updated with new function
signatures each time a new subclass is created. I need to find a way
to say that any given method is *purely* abstract, ie: that it will be
defined solely in the subclass.

Is there a way to do this, or am I pretty much stuck reimplementing
lots of functionality in each subclass?

Generics, along the lines Giovanni Azua showed you.

Giovanni said:
How about:

public abstract class A<N extends Number> {
void calculate() { put(my_func()); }
abstract N my_func();
void put(N myN) { set.add(myN); }
private final Set<N> set = new HashSet<N>();
}

public class B extends A<Long> {
@Override
Long my_func() { return Long.valueOf(1); }
}

AFAIK you can't do A generic without ressorting to reflection to get hold of
the right constructor for the Number subclass.

I don't understand what you mean exactly. 'A' is generic as you show it here.

'my_func()' should be named in accordance with the naming conventions, and
meaningfully, say 'getValue()'. The methods should probably be 'public'.
(And, of course, the classes should belong to packages.)
 
G

Giovanni Azua

Hi Lew,

Lew said:
I don't understand what you mean exactly. 'A' is generic as you show it
here.
Indeed you are right, I meant the generic not in the proper sense of
genericity but generic in the sense of A being concrete and reusable for all
cases without need to implement concrete subclasses "a generic solution" I
can't recall where I learned this second definition from ... :)
'my_func()' should be named in accordance with the naming conventions, and
meaningfully, say 'getValue()'. The methods should probably be 'public'.
(And, of course, the classes should belong to packages.)
I agree but you won't help and address the OP by completely changing her
example, I guess you will confuse her.

Best regards,
Giovanni
 
L

Lew

Lew wrote
Giovanni said:
Indeed you are right, I meant the generic not in the proper sense of
genericity but generic in the sense of A being concrete and reusable for all
cases without need to implement concrete subclasses "a generic solution" I
can't recall where I learned this second definition from ... :)

Lew wrote
Giovanni said:
I agree but you won't help and address the OP by completely changing her
example, I guess you will confuse her.

I hope not. horos11, if you are confused please feel free to ask more
questions and we'll work to clear it up.

Bad habits not caught early and corrected early are all the harder to correct.
Begin by doing things correctly. It's less to unlearn later.

The coding conventions are documented in
<http://java.sun.com/docs/codeconv/index.html>
(I admit, proudly, that I use the other convention for opening brace "{"
placement.)

More of your questions can be answered starting at the Java tutorials:
<http://java.sun.com/docs/books/tutorial/index.html>
and the links from there.
 
G

Giovanni Azua

Lew said:
The coding conventions are documented in
<http://java.sun.com/docs/codeconv/index.html>
(I admit, proudly, that I use the other convention for opening brace "{"
placement.)
I also don't like some of the Sun recommended ways of doing a few things
e.g. to have your implementation details (attributes) listed on top. It is
an implicit bottom-up way of design and thinking counter to the good OO
top-bottom design and good encapsulation. I don't want to see implementation
details, I'd rather like to see the public interface/methods of a class:
http://java.sun.com/docs/codeconv/html/CodeConventions.doc10.html

Regards,
Giovanni
 
L

Lew

Giovanni said:
I also don't like some of the Sun recommended ways of doing a few things
e.g. to have your implementation details (attributes) listed on top. It is
an implicit bottom-up way of design and thinking counter to the good OO
top-bottom design and good encapsulation. I don't want to see implementation
details, I'd rather like to see the public interface/methods of a class:
http://java.sun.com/docs/codeconv/html/CodeConventions.doc10.html

Used as I am to the conventional way of listing attributes prior to methods, I
found your listing jarring. I like to see things declared prior to their use,
a necessity within the body of methods and initializers, and a comforting
tradition for members. There's something that offends my sensibilities about
not knowing what a thing is until after its use.

Enums are a major exception to the tradition. Because their syntax requires
declaration of the constants before anything else, some of the conventions are
turned upside-down.

I recommend to newbies that they adhere to the convention of declaring member
variables prior to member methods, at least until they've gained enough
experience in Java to decide whether the other way is so superior in every
respect that it's worth violating the convention.

As for seeing the public interface first, that's what interfaces themselves
are for, and part of the motivation for "programming to the interface" as a
recommended practice.
 
M

Mark Space

I think I came up with the same thing Giovanni did, except "put" needs
to return a String to match your example.

(e-mail address removed) wrote:

abstract class a said:
{
String calculate() { return this.put(this.my_func()); }
abstract String put( U u );
abstract U my_func();

Otherwise use this the same way as his example.

Note: you can' parameterize with primitives. If you want to use float
or int, gotta write those by hand yourself. Sorry.
 
H

horos11

I think I came up with the same thing Giovanni did, except "put" needs
to return a String to match your example.

(e-mail address removed) wrote:



       abstract String put( U u );
       abstract U my_func();


Otherwise use this the same way as his example.

Note:  you can' parameterize with primitives.  If you want to use float
or int, gotta write those by hand yourself.  Sorry.

Ok, I guess I'll morph this issue a bit. I came to the conclusion that
generics were the way to go, but why should I need to define a
parameter with a class to do what I want to do?

I think of the types of variables in an object as implementation
details.. But the following doesn't work:

import java.util.*;
class AA
{

Set<?> example;

aa()
{
example = new HashSet<Integer>();
_setHelper(example, new Integer(1));
System.out.println(example);
}

private<K> void _setHelper(Set<K> parm, K key)
{
parm.add(key);
}
}

where I'm attempting to give the compiler a little push in the right
direction, showing that Set<K> should be linked with the ?. I would
have thought this would have worked, but no.

Of course, if I explicitly cast it - (Set<Integer>)example, it works,
but that gets rid of the point of generics, doesn't it?

So any ideas around this?

(ps - wrt language lawyering, with all respect I detest camelcase, and
will only use it if required by convention. And no - I don't go around
naming my variables mySet, etc.. I do it for example.. so thanks for
the concern, but no thanks..
 
H

horos11

BTW - with the below I did find a workaround. If I say:

private<K> void _setHelper(Set<K> parm, Integer key)
{
parm.add((K) key);
}

ie, ie explicitly cast it, this works. But it also tells me that I'm
using unsafe operations.
This should not be unsafe - there's got to be a better solution than
this out there. Else are generics inherently unsafe?
 
L

Lew

Ok, I guess I'll morph this issue a bit. I came to the conclusion that
generics were the way to go, but why should I need to define a
parameter with a class to do what I want to do?

Because that's how Java does it.
I think of the types of variables in an object as implementation
details.. But the following doesn't work:

import java.util.*;
class AA
{

Set<?> example;

aa()

The constructor name must match the class name. This line as shown will not
compile, as it is legal for neither constructor nor method.

Both class and constructor must be public if you wish to use them outside the
package in which they're defined.
{
example = new HashSet<Integer>();
_setHelper(example, new Integer(1));
System.out.println(example);
}

private<K> void _setHelper(Set<K> parm, K key)

Convention has it that one not use underscores in method names.

To your actual point, 'Set<?>' and 'Set<K>' have different meanings. Just
telling the method that the 'Set<?>' is actually a 'Set<Integer>' isn't quite
enough. Generally, with "extends" wildcards (? is shorthand for "? extends
Object"), you cannot safely "put()" (i.e., "add()" in this context).

See these articles:
<http://java.sun.com/docs/books/tutorial/extra/generics/index.html>
particularly,
<http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html>

<http://www.ibm.com/developerworks/java/library/j-jtp04298.html>
<http://www.ibm.com/developerworks/java/library/j-jtp07018.html>

The compiler errors will indicate what you did wrong, but in more general
terms, you aren't locking down your type analysis with this kind of thing. If
'example' is meant to be a 'Set<Integer>', it should be declared as such. If
the whole class is meant to be a general handler for different types of sets,
where the instance will deal throughout with the same type, then the class
itself should have the type parameter. Also, there's little point in passing
a member variable as an argument to a member method of the same class. It
already has access to the member variable.
{
parm.add(key);
}
}

where I'm attempting to give the compiler a little push in the right
direction, showing that Set<K> should be linked with the ?. I would
have thought this would have worked, but no.

That's because you are misusing the generics syntax. The right way to do this
is to have the <K> in the 'Set' declaration itself. You were trying to tell
the compiler that 'Set' can have literally any type of object in it with the
<?>, and also simultaneously that it can only have 'K' (in this case,
'Integer') in it. You can't get both promises at the same time because they
contradict each other.

Furthermore, <?> means that whatever type 'Set' contains, all its elements are
of that type. If your method were legal, it could be called at different
times with different 'K' types, all trying to 'add()' to the same set. That
wouldn't be legal either.
Of course, if I explicitly cast it - (Set<Integer>)example, it works,
but that gets rid of the point of generics, doesn't it?

It does generate a warning to that effect.

It was the failure to lock down the 'example' type parameter to that of the
method that got rid of that point, actually.
So any ideas around this?

Do it like this:

public class AA
{

Set<Integer> example = new HashSet<Integer>();

public void loadAndPrintln()
{
example.add( Integer.valueOf(1) );
System.out.println( example );
}
}

If you want 'AA' to be generic so that client code can use it for 'Integer',
'String' or whatever, the generic parameter should be on the class itself.

public class AA <K>
{
Set <K> example = new HashSet <K> ();

public void loadAndPrintln( K value )
{
example.add( value );
System.out.println( example );
}
}

That's kind of the point of generics, isn't it?
(ps [sic] - wrt language lawyering, with all respect I detest camelcase, and
will only use it if required by convention. And no - I don't go around

It is "required" by convention. It is not a question of "language lawyering",
as you so disparagingly put it, but of communication. The language itself
lets you do things differently, but that doesn't mean that you should do
things differently. The conventions make life easier in a world where one is
not the only resident.

However, whatever convention you do follow, the constructor name must match
the case of the class name. The compiler will refuse to cooperate if you don't.
naming my variables mySet, etc.. I do it for example.. so thanks for
the concern, but no thanks..

One period suffices to indicate a declarative sentence.
 
L

Lew

BTW - with the below I did find a workaround. If I say:

private<K> void _setHelper(Set<K> parm, Integer key)
{
parm.add((K) key);
}

ie, ie explicitly cast it, this works. But it also tells me that I'm
using unsafe operations.
This should not be unsafe - there's got to be a better solution than
this out there. Else are generics inherently unsafe?

No, generics make life more safe. What you did intentionally broke the
promises that generics tries to keep, so that was what was unsafe.

If you read the rules for generics, you will see that they are compile-time
constructs, and that casts to a parametric type, being a run-time phenomenon,
are therefore not really what generics handle. Thus the warning.

Correct use of generics, which follows hard on correct if difficult detailed
type analysis, will eliminate both the need for the cast and the warning.
 
M

Mark Space

BTW - with the below I did find a workaround. If I say:

private<K> void _setHelper(Set<K> parm, Integer key)
{
parm.add((K) key);
}

ie, ie explicitly cast it, this works. But it also tells me that I'm
using unsafe operations.
This should not be unsafe - there's got to be a better solution than
this out there. Else are generics inherently unsafe?

No, they're safe, just the way you are using them isn't.

First, I want to point out that if you follow Giovanni's advice, the end
user never sees the generic declaration.

class AA<T> {}

class BB extends AA<Integer> {}

The user just uses BB as a normal class:

BB bb = new BB();

So I don't see why you want to get rid of generics. However, if you do,
then I think something like this will work:

class AA {}

class BB {} extends AA {
Set<Integer> example;
BB() {
example = newHashSet<Integer>();
example.add( new Integer() );
System.out.println( example );
}
}

No need for the helper method, but in this case you do need to declare
the Set<> yourself (which you were basically doing anyway when you
called "new").
 
T

Tom Anderson

Ok, I guess I'll morph this issue a bit. I came to the conclusion that
generics were the way to go, but why should I need to define a parameter
with a class to do what I want to do?

This has been discussed here many times before. The upshot is that because
of the way java's generics work, you can't get away from defining the
parameter as part of the exposed interface. You require clients to write:

HorosFunkyClass<?>

Instead of just:

HorosFunkyClass

When dealing with it polymorphically. This is a wart, but a small one.

However ...

I have thought of a way you could do it without the wart, using
deviousness.

The trick is to push the variable into another, private, class, and then
refer to it via a <?>-bound variable. You can then manipulate that object
via a private generic method, which provides a local type-bound context to
do the work in. I should warn you that this is third-level generics
voodoo.

Here we go:

abstract class FunkyClass {
private FunkyHelper<?> helper;

protected FunkyClass(FunkyHelper<?> helper) {
this.helper = helper;
}
public void calculate() {
doCalculate(helper);
}
private <T> void doCalculate(FunkyHelper<T> helper) {
helper.things.add(helper.myFunc());
}
}

class IntegerFunky extends FunkyClass {
public IntegerFunky() {
super(new IntegerFunkyHelper());
}
}

class FloatFunky extends FunkyClass {
public FloatFunky() {
super(new FloatFunkyHelper());
}
}

abstract class FunkyHelper<T> {
public Set<T> things;
public abstract T myFunc();
}

class IntegerFunkyHelper extends FunkyHelper<Integer> {
public Integer myFunc() {
return 1;
}
}

class FloatFunkyHelper extends FunkyHelper<Float> {
public Float myFunc() {
return 1.0f;
}
}

Study and be enlightened.

tom
 
R

Roedy Green

Is there a way to do this, or am I pretty much stuck reimplementing
lots of functionality in each subclass?

this sort of problem is sometimes solved with a set of has-a functions
rather than is-a.

You provide the functionality via a delegate object referred to by the
class. Think of it as hiring specialised servants rather that doing
all the work yourself.

see http://mindprod.com/jgloss/callback.html
http://mindprod.com/jgloss/delegate.html
http://mindprod.com/jgloss/isa.html
--
Roedy Green Canadian Mind Products
http://mindprod.com

"It wasn’t the Exxon Valdez captain’s driving that caused the Alaskan oil spill. It was yours."
~ Greenpeace advertisement New York Times 1990-02-25
 

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,968
Messages
2,570,154
Members
46,702
Latest member
LukasConde

Latest Threads

Top