Re: JDK1.5, improved FOR loop and generics - How?!

  • Thread starter Jesper Nordenberg
  • Start date
J

Jesper Nordenberg

Roedy Green said:
Exactly. I suggest the notion of LIKE. You can declare a temporary
variable like some other variable or method result. That way your
temporary automatically tracks. e.g. selects long instead of int, when
the master template variable is grown or shrunk.

Yes, it would be nice to get rid of the variable type declaration and
write for example:

var x = myObject.getSomething();
x.someMethod();

I think the reason why Sun is not likely to add this feature to the
Java language is that you could potentially run into trouble if you
change the return type of getSomething() to a class that have a
someMethod() with different semantics than the original someMethod().
Today you can only change the return type to a sub class of the
original class/interface, and thus the someMethod() is guaranteed to
have the same sematics.

/Jesper Nordenberg
 
P

Phillip Lord

Jesper> Yes, it would be nice to get rid of the variable type
Jesper> declaration and write for example:

Jesper> var x = myObject.getSomething(); x.someMethod();


The problem here is that Java's type calculus is not just not clever
enough and therefore requires an lot of programmer annotation of the
code to say anything useful.

What you want is something like this SML. Given this definition of a
function (calculating the factoral) it tells you....

fun fact 0 = 1
| fact n = n * fact(n-1);

that this function takes an int and returns an int. It knows this
because of it knows the factoral of 0 is 1 which is an int.

val fact = fn : int -> int


Java's type system is just not that rich. Even if you come up with
specific solutions where you can do omit the type declaration you
probably can't in general and still have Java give you the guarantees
that you expect.

Cheers

Phil
 
H

Hans Kratz

Phillip said:
The problem here is that Java's type calculus is not just not clever
enough and therefore requires an lot of programmer annotation of the
code to say anything useful.

I don't think that the verbosity mandated by Java is a problem. I see it
more as an advantage considering that it improves the readability and
maintainability of source code. Furthermore with modern Java IDEs you
can add the necessary type declaration with one or two keystrokes.

When using the advanced type inference mechanism in Standard ML I had to
constantly ask myself if the result of this or that expression is now a
list of tuples of lists or a tuple of lists of lists. ;-)


Best regards,


Hans
 
R

Roedy Green

I don't think that the verbosity mandated by Java is a problem. I see it
more as an advantage considering that it improves the readability and
maintainability of source code.

It is nice to READ, but not to maintain. When a type changes, there
is no easy way to change all the instances of that type that should
change and leave the rest intact. Further, when you screw up, you
often don't find out till the program is running in production.
 
H

Hans Kratz

Roedy said:
It is nice to READ, but not to maintain. When a type changes, there
is no easy way to change all the instances of that type that should
change and leave the rest intact.

What kind of "type change" are you referring to? Adding a
method/field/etc. obviously does not cause any problems. The name of a
type can be easily changed with a renaming tool. If the return type of a
method is changed than it seems likely that all invocations have to be
adapted somehow anyway.
Further, when you screw up, you
often don't find out till the program is running in production.

Huh? Java contains all those strong compile-time checks to prevent just
that.


Best regards,


Hans
 
J

Jesper Nordenberg

Hans Kratz said:
I don't think that the verbosity mandated by Java is a problem. I see it
more as an advantage considering that it improves the readability and
maintainability of source code. Furthermore with modern Java IDEs you
can add the necessary type declaration with one or two keystrokes.

True, the gains of automatically inferred types of local variables
would not be substantial. The real gain would be a more powerful type
system for generic classes and methods. The current Java generics
suggestion is not very powerful and has a lot of annoying properties.
When using the advanced type inference mechanism in Standard ML I had to
constantly ask myself if the result of this or that expression is now a
list of tuples of lists or a tuple of lists of lists. ;-)

Of course these kind of problems could also be solved by a good IDE
that infers the type of a variable while you type and uses that
information to provide code completion etc., just like a normal Java
IDE.

/Jesper Nordenberg
 
P

Phillip Lord

Hans> I don't think that the verbosity mandated by Java is a
Hans> problem. I see it more as an advantage considering that it
Hans> improves the readability and maintainability of source
Hans> code. Furthermore with modern Java IDEs you can add the
Hans> necessary type declaration with one or two keystrokes.

It's not the verbosity which is irritating, its the duplication. You
have to tell Java things that you want it to just know.


Hans> When using the advanced type inference mechanism in Standard
Hans> ML I had to constantly ask myself if the result of this or
Hans> that expression is now a list of tuples of lists or a tuple of
Hans> lists of lists. ;-)


This I don't understand. I have this problem when I write lisp, but
with SML it should tell you whether its a list of tuples of lists...

I'm not actually advocating SML's type system as perfect. I think its
just an interesting example of what can be done.

Phil
 
N

Neal Gafter

Jesper said:
True, the gains of automatically inferred types of local variables
would not be substantial. The real gain would be a more powerful type
system for generic classes and methods. The current Java generics
suggestion is not very powerful and has a lot of annoying properties.

Can you please be more specific?
 
?

=?ISO-8859-1?Q?Daniel_Sj=F6blom?=

Neal said:
Can you please be more specific?

Type erasure. Prevents a lot of perfectly sensible generic code. No
generic arrays. No primitive template instantiations. No generic methods
like (sorry for the C++ syntax, I don't remember the java syntax off-hand):

template <typename Sequence>
char charAt(Sequence s, int index)
{
return s.charAt(index);
}

(This would have been useful pre 1.4 since you can't extend String nor
StringBuffer.)

But this was part of the design constraints, I understand. I.e. no
breaking of backwards compatibility. So in that respect, I think the
generics are rather nice.
 
H

Hans Kratz

Phillip said:
Hans> When using the advanced type inference mechanism in Standard
Hans> ML I had to constantly ask myself if the result of this or
Hans> that expression is now a list of tuples of lists or a tuple of
Hans> lists of lists. ;-)

This I don't understand. I have this problem when I write lisp, but
with SML it should tell you whether its a list of tuples of lists...

If the developer makes heavy use of type inference he omits type
declarations for local variables, return types and parameters of
functions (just as in your factorial example). The omitted information
makes the code much harder to read/maintain especially if functional
language constructs such as map, foldl, etc. are heavily used.

Thus I think it is good that the language requires type declaration for
local variables, method parameters, return types, ...

This would make it much harder to write ugly code like the following
snippet taken from an OCR project I coauthored a long time ago. ;-)

--- snip ---
local
fun posOf(x,[])=0|
posOf(x,y::ys)=if x=y then 0 else 1+posOf(x,ys);
in
fun displacement(h1,h2) =
let val n = (length h1) + (length h2) + 1; val d = length h2 in
let val list = List.tabulate(n, fn x => histDiff(h1,h2,x - d)) in
posOf((foldl Int.min (hd list) list),list)-d
end
end;
end;
--- snip ---


Best regards,


Hans
 
R

Roedy Green

What kind of "type change" are you referring to?

If you changed the name of the type of a Dog collection to Canine, you
have many Dog temporary variables in your program that need to change
to Canine, but some of them, not related to the collection need to
stay at Dog. There is no tight linking of the types of collections
and the types of the temporaries used to access them.
 
R

Roedy Green

Huh? Java contains all those strong compile-time checks to prevent just
that.

With collections (at least in the 1.4 days) you have casts from object
back to something. You don't find out till run time if you have
erred. You can never exercise every line of code.
 
R

Roedy Green

The omitted information
makes the code much harder to read/maintain especially if functional
language constructs such as map, foldl, etc. are heavily used.

It makes it harder to read but easier to maintain since you have less
to maintain.

In a SCID situation, you could declare a variable as LIKE something
else, e.g. like the type of a collection, but it would display as what
it actually was. The LIKE is really a note to the scid to
automatically change the type of this variable if the base variable's
type were changed.

Then you get he benefit of ease of reading and ease of maintenance.
 
N

Neal Gafter

Daniel said:
Type erasure. Prevents a lot of perfectly sensible generic code. No
generic arrays. No primitive template instantiations. No generic methods
like (sorry for the C++ syntax, I don't remember the java syntax off-hand):

template <typename Sequence>
char charAt(Sequence s, int index)
{
return s.charAt(index);
}

(This would have been useful pre 1.4 since you can't extend String nor
StringBuffer.)

But this was part of the design constraints, I understand. I.e. no
breaking of backwards compatibility. So in that respect, I think the
generics are rather nice.

I haven't run into a situation in which erasure actually constrained the
compile-time programming model in any practical sense. Instead of generic
arrays you have generic collections. We do have generic methods, though for the
example you suggest they're not needed. The following is perfectly legal in
Java 1.5, and works with String, StringBuffer, and many other classes, and
doesn't require generics:

public static char charAt(java.lang.CharSequence s, int index) {
return s.charAt(index);
}

I still don't see the point of your concerns.

-Neal
 
P

Phillip Lord

Hans> Phillip Lord wrote: When using the advanced type inference
Hans> mechanism in Standard ML I had to constantly ask myself if the
Hans> result of this or that expression is now a list of tuples of
Hans> lists or a tuple of lists of lists. ;-)
Hans> If the developer makes heavy use of type inference he omits
Hans> type declarations for local variables, return types and
Hans> parameters of functions (just as in your factorial
Hans> example). The omitted information makes the code much harder
Hans> to read/maintain especially if functional language constructs
Hans> such as map, foldl, etc. are heavily used.

Okay I understand your point now.

As the system could always tell you what the type is, to some extent
this is a question of tooling. Ideally you should be able to switch
the display on or off. But I still think that advantage of not
requiring the programmer to write it is good.

Phil
 
C

Chris Uppal

Daniel said:
[...] No primitive template instantiations. No generic methods
like (sorry for the C++ syntax, I don't remember the java syntax
off-hand):

template <typename Sequence>
char charAt(Sequence s, int index)
{
return s.charAt(index);
}

If I'm not misunderstanding your intent, you /can/ do that kind of thing:

======================
import java.util.List;

public class Test
{
public static <E> E
nth(List<E> list, int i)
{
return list.get(i);
}
}
======================

Primitive types are a major disapointment, though*.

If it helps, don't confuse Java's generics with C++'s templates -- they are
different beasts. In the same sense that C++ templates are macros dressed up
in fancy clothes, Java's generics are casts in a short skirt and high heels.

-- chris

[*] This sentence can be understood in two way -- I mean both of them ;-)
 
K

Kirk Woll

Neal Gafter said:
I haven't run into a situation in which erasure actually constrained the
compile-time programming model in any practical sense. Instead of generic
arrays you have generic collections. We do have generic methods, though for the
example you suggest they're not needed. The following is perfectly legal in
Java 1.5, and works with String, StringBuffer, and many other classes, and
doesn't require generics:

public static char charAt(java.lang.CharSequence s, int index) {
return s.charAt(index);
}

I still don't see the point of your concerns.

-Neal

I find type erasure causes generic code to become very unintuitive.
Take the class:

class A<T> {
HashMap map = new HashMap();

T getElement(String id) {
Object o = map.get(id);

// Not allowed; generates a compile-time error !!! {
if (o instanceof T)
return (T)o;
else
return null;
// }

// Not allowed; doesn't do anything {
try {
return (T)o;
} catch (ClassCastException e) {
return null;
}
// }
}
}

Assume the hash map can have any type of object inside. Given that T
is supposed to (in theory if not practice) represent the type of the
return method in this example, it's confounding at first and
frustrating still, to find it is impossible to create a method of this
sort that will be guaranteed not to throw a ClassCastException on the
caller of this method.
 
N

Neal Gafter

Kirk said:
Assume the hash map can have any type of object inside. Given that T
is supposed to (in theory if not practice) represent the type of the
return method in this example, it's confounding at first and
frustrating still, to find it is impossible to create a method of this
sort that will be guaranteed not to throw a ClassCastException on the
caller of this method.

See Collections.checked* methods to see how to do this.
 
?

=?ISO-8859-1?Q?Daniel_Sj=F6blom?=

(I just want to clarify. I din't write the above. Maybe the OP has
something more to add.)
I haven't run into a situation in which erasure actually constrained the
compile-time programming model in any practical sense. Instead of
generic arrays you have generic collections.

It is mostly a performance issue. Autoboxed primitives are also slower
(and require more memory.)
We do have generic
methods, though for the example you suggest they're not needed.

No, not anymore, but see below.
The
following is perfectly legal in Java 1.5, and works with String,
StringBuffer, and many other classes, and doesn't require generics:

public static char charAt(java.lang.CharSequence s, int index) {
return s.charAt(index);
}

But this is not equivalent to my method. That only works on
CharSequences (which wasn't introduced until 1.4), my example works on
any class that has a char charAt(int) method. As it is now, we have to
wait until you guys decide that String or StringBuffer (or any other
classes for that matter) should implement this or that interface until
we can use them generically.

And just creating more and more interfaces to deal with this is not
really an alternative, as it is often redundant, and it requires
changing old code, which sometimes cannot be done.
I still don't see the point of your concerns.

Besides the above, java generics also lack many of the aspects of C++
template metaprogramming, like (partial) template specialization and
constant value templates. C++ templates are actually Turing complete.
But this is not something I miss, really.

But how about templates as template arguments:

template <template<class> class T, typename T2>
class SomeClass
{
T<T2> templateOfTemplateMember;
};

This can be useful at times. But as I said, I quite like the generics,
but that doesn't mean they are perfect.
 
K

Kirk Woll

Neal Gafter said:
See Collections.checked* methods to see how to do this.

Thanks for the response, Neal, but I'm aware it's possible to
literally pass the Class type that you are trying to check for and use
its isInstance method. But the point I was trying to make is
intuitively, this information should already be present because of the
generic type (and would be present without type erasure) specified on
the class.

The example you sited is a static method that wraps an already typed
collection (type E) but still requires you to supply the class type.
Thus, for a collection of strings, you would have:

Collections.checkedCollection(new ArrayList<String>(), String.class);

What I find unannoying and unintuitive is the need to supply
"String.class" when the type of the collection is already supplied via
"new ArrayList<String>()". I guess ultimately this is just an
inconvenience, but seeing all this redundant code really clashes with
the whole spirit of generics.

Kirk
 

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,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top