enums, using methods as initializers

M

Mikhail Teterin

Hello!

I would like to be able to initialize fields of an enum with /methods/ (of
another Class).

Here is the (non-working) example:

import java.util.*;
import java.sql.*;

public enum Field {
FIELD1 (ResultSet.getString),
FIELD2 (ResultSet.getDouble),
...
FIELDN (ResultSet.getTimestamp);

private java.lang.reflect.Method extract;
}

the idea is to be able to get all fields from a given ResultSet by going
through the list of Fields and extracting the column from the ResultSet.

Something like:

public void print(ResultSet rs)
{
for (Field f : Field.values())
System.out.println(f + ":\t" + rs.f.extract(f));
}

Does the above stand a chance of being turned into a real Java code?

Thanks for ideas!

-mi
 
D

Daniel Pitts

Mikhail said:
Hello!

I would like to be able to initialize fields of an enum with /methods/ (of
another Class).

Here is the (non-working) example:

import java.util.*;
import java.sql.*;

public enum Field {
FIELD1 (ResultSet.getString),
FIELD2 (ResultSet.getDouble),
...
FIELDN (ResultSet.getTimestamp);

private java.lang.reflect.Method extract;
}

the idea is to be able to get all fields from a given ResultSet by going
through the list of Fields and extracting the column from the ResultSet.

Something like:

public void print(ResultSet rs)
{
for (Field f : Field.values())
System.out.println(f + ":\t" + rs.f.extract(f));
}

Does the above stand a chance of being turned into a real Java code?

Thanks for ideas!

-mi
Yes, kind of. You won't be able to pass in a method, but you can create
a delegate method easily.
I have an example here actually:
<http://virtualinfinity.net/wordpress/program-design/2007/10/22/using-enums-as-a-flyweight-pattern/>

enums are full classes, so you can add methods to them, and even add an
abstract method to the base enum type (Field in your case) and override
those methods in the subtypes (FIELD1 FIELD2, etc...) .
 
M

Mikhail Teterin

Daniel said:
Yes, kind of.  You won't be able to pass in a method, but you can create
a delegate method easily.
:(

I have an example here actually:
<http://virtualinfinity.net/wordpress/program-design/2007/10/22/using-enums-as-a-flyweight-pattern/>

In your example, each case of the enum spells-out its methods in full.
It is workable, of course, but I wanted to have list the cases as a kind
of a /table/ -- preferably one case per line.

I'm pretty certain, I can do this with my own /data/:

FIELD1 ("string"),
FIELD2 ("double"),
...
FIELDN ("Timestamp);

private String type;

and then use the type to tell me, which of method of the foreign class to
call:

if (type == "string")
return rs.getString(......)
if (type == "double")
return rs.getDouble(......)
.... a case for each type ....

But it would all have been much easier, if I could pass the
/methods/ the same way I can pass function-pointers in C or C++.

Thanks!

-mi
 
D

Daniel Pitts

Mikhail said:
In your example, each case of the enum spells-out its methods in full.
It is workable, of course, but I wanted to have list the cases as a kind
of a /table/ -- preferably one case per line.

I'm pretty certain, I can do this with my own /data/:

FIELD1 ("string"),
FIELD2 ("double"),
...
FIELDN ("Timestamp);

private String type;

and then use the type to tell me, which of method of the foreign class to
call:

if (type == "string")
return rs.getString(......)
if (type == "double")
return rs.getDouble(......)
.... a case for each type ....

But it would all have been much easier, if I could pass the
/methods/ the same way I can pass function-pointers in C or C++.

Thanks!

-mi
You can use reflection in this case, but thats not necessarily a good
idea. Reflection can add unnecessary complexity.

I gather from your previous posts that you are used to programming in
C/C++, and finding more concise manors to express a particular effect of
code. Just remember, more lines doesn't mean more complex. In fact,
/sometimes/ it means less complex :)

Like I said, you *can* use reflection for this, but I advise against it:
<http://virtualinfinity.net/wordpres...angers-of-reflection-or-put-down-that-mirror/>

What you're trying to do sounds a lot like something that I did a while
ago. It also sounds like you would be better off using Hibernate or some
other ORM solution. Trust me, the ramp-up time is well-worth the
maintenance costs down the road.
 
M

Mikhail Teterin

Daniel said:
You can use reflection in this case, but thats not necessarily a good
idea. Reflection can add unnecessary complexity.

Maybe, one can just treat all data-fields of a class as a Collection or some
such?

class Meow {
String foo;
double bar;
}

....

for (Field field : Meow.fields()) {
if (field.getType() == String)
.....

?
I gather from your previous posts that you are used to programming in
C/C++, and finding more concise manors to express a particular effect of
code. Just remember, more lines doesn't mean more complex. In fact,
sometimes it means less complex :)

The idea here is that the concise declarative part can be maintained by
someone else as "data", while I maintain the code...

The shorter the program, the fewer screenfuls it takes, the fewer bugs :)

Thanks!

-mi
 
D

Daniel Pitts

Mikhail said:
The idea here is that the concise declarative part can be maintained by
someone else as "data", while I maintain the code...

The shorter the program, the fewer screenfuls it takes, the fewer bugs :)
Not necessarily. Less verbosity *can* lead to fewer bugs, but it can
also be too terse to understand. In any case, I think that this
situation *is* ripe for a better solution... I've suggested it before.
Hibernate! Google for it. Use it. You no longer have to deal with
low-level JDBC stuff, it'll help manage your schema for you if you
choose, and the CRUD operations are super easy.
No problem. If you choose *not* to use Hibernate, a response of why
would be appreciated.


Daniel.
 
M

mekane

Mikhail said:
Hello!

I would like to be able to initialize fields of an enum with /methods/ (of
another Class).

Here is the (non-working) example:

import java.util.*;
import java.sql.*;

public enum Field {
FIELD1 (ResultSet.getString),
FIELD2 (ResultSet.getDouble),
...
FIELDN (ResultSet.getTimestamp);

private java.lang.reflect.Method extract;
}

the idea is to be able to get all fields from a given ResultSet by going
through the list of Fields and extracting the column from the ResultSet.

Something like:

public void print(ResultSet rs)
{
for (Field f : Field.values())
System.out.println(f + ":\t" + rs.f.extract(f));
}

Does the above stand a chance of being turned into a real Java code?

Thanks for ideas!

-mi

I assume you've looked at:
http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html

I had a case where I needed to do something similar to this, and I tried
overriding a method on each element of the enum. I didn't like defining
big methods inside the constructor, so I actually went with the method
described in the article that uses a switch.

So you would have one method defined in the enum like:

public String extract( Resultset arg ){
switch ( this )
{
case FIELD1:
return arg.getString();
case FIELD2:
return arg.getDouble();
...
case FIELDN:
return resultSet.getTimestamp();
}
}

then you could iterate over the values of the enum and do f.extract(rs)

-marty
 
D

Daniel Pitts

mekane said:
I assume you've looked at:
http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html

I had a case where I needed to do something similar to this, and I tried
overriding a method on each element of the enum. I didn't like defining
big methods inside the constructor, so I actually went with the method
described in the article that uses a switch.

So you would have one method defined in the enum like:

public String extract( Resultset arg ){
switch ( this )
{
case FIELD1:
return arg.getString();
case FIELD2:
return arg.getDouble();
...
case FIELDN:
return resultSet.getTimestamp();
}
}

then you could iterate over the values of the enum and do f.extract(rs)

-marty
That is very specifically a Bad Idea!
f.extract should NOT have a switch statement, but instead should be
polymorphic.
 
M

mekane

That is very specifically a Bad Idea!
f.extract should NOT have a switch statement, but instead should be
polymorphic.

What difference does it make? Anything other than I might forget to add
another case?
Is this more than just an implementation detail?
 
D

Daniel Pitts

mekane said:
What difference does it make? Anything other than I might forget to add
another case?
Is this more than just an implementation detail?
Yes, it is far more than an implementation detail, it is a design principal.

Switch statements should be avoided. I know this is going to sound
snobby, but polymorphic behavior is far superior for this situation.
Not only is it likely to have better performance, it is easier to
refactor into a more useful idiom. Say someone wants to add a custom
field extractor, its easy to change these enums into a regular class,
and have the extract be a method in an interface. That way, the client
can say "extract this field with this approach."
 
M

mekane

Daniel said:
Yes, it is far more than an implementation detail, it is a design
principal.

Switch statements should be avoided. I know this is going to sound
snobby, but polymorphic behavior is far superior for this situation. Not
only is it likely to have better performance, it is easier to refactor
into a more useful idiom. Say someone wants to add a custom field
extractor, its easy to change these enums into a regular class, and have
the extract be a method in an interface. That way, the client can say
"extract this field with this approach."

I see. That makes sense, and I would agree that polymorphism is much
more elegant. But isn't the point of an enum to say "here are all the
possible values of this type, that's it". So a better design decision
here would be to use something other than enums in the first place.
Especially if you can't say for sure that the fields will never change.

To me, an enum and a switch work nicely together, especially when the
alternative is to write different versions of a big, complicated method
in the definition of an enum.

I'm not trying to argue, I'm just expressing an opinion.

Would you never use a switch?
 
D

Daniel Pitts

mekane said:
I see. That makes sense, and I would agree that polymorphism is much
more elegant. But isn't the point of an enum to say "here are all the
possible values of this type, that's it". So a better design decision
here would be to use something other than enums in the first place.
Especially if you can't say for sure that the fields will never change.

To me, an enum and a switch work nicely together, especially when the
alternative is to write different versions of a big, complicated method
in the definition of an enum.

I'm not trying to argue, I'm just expressing an opinion.

Would you never use a switch?
I very much try to avoid switch (or if/elseif/elesif,etc..) as much as
feasible.

Switch is a remnant of procedural programming languages. Often times it
was used to create polymorphic behavior based on a "type" token. Well,
now you have a "type" that can do that polymorphic behavior for you.

I'm not saying there are NEVER times when you can use switch statements,
I'm just saying that by the time I need one switch statement, I probably
need two, and at that point its time to use polymorphism and create an
abstract method for each of my switch statements. As a mater of fact, I
would *love* a tool that could take an switch(enum) and convert it to
enum.method().

Hear that JetBrains? Make it happen :)
 
L

Lew

Daniel said:
Hibernate! Google for it. Use it. You no longer have to deal with
low-level JDBC stuff, it'll help manage your schema for you if you
choose, and the CRUD operations are super easy.
... If you choose *not* to use Hibernate, a response of why
would be appreciated.

I'm learning Hibernate, and the JPA annotations generally. It's a bit tricky
learning to configure the DataSource, but I'm slogging through it.

I've written whole entire data-access layers, the most recent replete with
generic <Entity> typing and all kinds of nifty transaction boundaries and
exception logging - whew. I am really hoping the Hibernatic approach will
make life easier. It may seem easy to do database, but to do it right, with
rigor and reliability takes a lot.

Having labored through the "by-hand" approach, I really get where the
annotations are coming from.

The devil is in the deployment.
 
L

Lew

Daniel said:
I very much try to avoid switch (or if/elseif/elesif,etc..) as much as
feasible.

Switch is a remnant of procedural programming languages. Often times it
was used to create polymorphic behavior based on a "type" token. Well,
now you have a "type" that can do that polymorphic behavior for you.

I'm not saying there are NEVER times when you can use switch statements,
I'm just saying that by the time I need one switch statement, I probably
need two, and at that point its time to use polymorphism and create an
abstract method for each of my switch statements. As a mater of fact, I
would *love* a tool that could take an switch(enum) and convert it to
enum.method().

Hear that JetBrains? Make it happen :)

One major advantage of the polymorphic approach is that you get compiler
enforcement. You cannot "fall" into an unexpected case, or forget to
implement a behavior.

In fact, I find the quirky combination of the class attitude and the enum
constant ancestry along with the peculiarities of Java's implementation as a
pseudo-inherited Enum class with occasional implicit inner classes extending
the enum to be a strangely, emergently powerful mechanism. For one thing,
enums may hold the power to release us from the temptation to reflection.

Back to the OP's question, Daniel, were you thinking of something like this,
only maybe better refactored?

You'd use it something like:

Object val =
Noom.valueOf( rsMetaData.getColumnType( col ) )
.getValue( rs, col );

(throws NPE)

<sscce>
public enum Noom
{
BOOLEAN( Types.BOOLEAN )
{
@Override
public Boolean getValue( ResultSet rs, int column )
{
try
{
return (rs.getObject( column ) == null? null :
Boolean.valueOf( rs.getBoolean( column )));
}
catch ( SQLException ex )
{
logger.error( "SQL Exception"+ ex.getMessage(), ex );
return null;
}
}

}
,
VARCHAR( Types.VARCHAR )
{
@Override
public String getValue( ResultSet rs, int column )
{
try
{
return rs.getString( column );
}
catch ( SQLException ex )
{
logger.error( "SQL Exception"+ ex.getMessage(), ex );
return null;
}
}

}
;
private final int sqlType;
private Noom( int sqlT )
{
this.sqlType = sqlT;
}

public static Noom valueOf( int sqlT )
{
for ( Noom noom : values() )
{
if ( noom.sqlType == sqlT )
{
return noom;
}
}
return null;
}

private static final Logger logger = Logger.getLogger( Noom.class );

public abstract Object getValue( ResultSet rs, int column );
}
</sscce>
 
M

mekane

One major advantage of the polymorphic approach is that you get compiler
enforcement. You cannot "fall" into an unexpected case, or forget to
implement a behavior.

Agreed. I like compiler enforcement.
</sscce>
snip
</sscce>

That example from Lew may have just completely swayed me. I figured that
writing methods inside enum definitions would be hideous, but that
example was quite nice looking. I'm going to refactor a hobby project
I'm working on and see how it goes. I was originally going to use the
polymorphic approach, but I went with a switch instead.

Thanks for the interesting discussion.

-marty
 
M

Mark Space

Mikhail said:
Hello!

I would like to be able to initialize fields of an enum with /methods/ (of
another Class).

Here is the (non-working) example:

import java.util.*;
import java.sql.*;

The important bit for me is that last line. SQL? Doesn't SQL already
have some methods for dealing with tabular data? Trying to shoe-horn
this into an enum seems like a bad idea. Use what's there already, it's
likely to be far more useful and flexible in the long run. Enums are
likely to box you into a corner.
 
M

Mikhail Teterin

Mark said:
The important bit for me is that last line.  SQL?  Doesn't SQL already
have some methods for dealing with tabular data?

It does -- there are getString(), getInt(), getDouble(), etc.

The problem I'm facing is that my rows return A LOT of columns, which must
all be tediously assigned to fields of a class. This is, roughly, what I do
in the constructor (each row creates an object of type Entry):

public class Entry
{
public String foo;
public double bar;
...
public Date woof;

public Entry(ResultSet rs)
{
foo = rs.getString("foo");
bar = rs.getDouble("bar");
...
woof = rs.getTimestamp("woof");
}
}

What I'm looking for is a way to go through all fields and extract them from
the row in a loop. Something like:

public Entry(ResultSet rs) {
for (WHAT? field : FieldsOfEntry?) {
field = rs.MethodForField(field.toString());

}
}

This would allow me to add/remove fields without changing the code every
time. Sort of make it "data-driven" with the fields of the class themselves
being the "data".

I'll look up "Hibernate", but I was hoping, a solution can be found, since
Java (unlike C) keeps the fields' names and types around at run-time
anyway...

Thanks!

-mi
 

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

No members online now.

Forum statistics

Threads
473,733
Messages
2,569,440
Members
44,830
Latest member
ZADIva7383

Latest Threads

Top