6

Its often hear that Haskell(which I don't know) has a very interesting type system.. I'm very familiar with Java and a little with C#, and sometimes it happens that I'm fighting the type system so some design accommodates or works better in a certain way.

That led me to wonder...

What are the problems that occur somehow because of deficiencies of Java/C# type system? How do you deal with them?

Camilo Díaz Repka
  • 4,805
  • 5
  • 43
  • 68
  • Also see [what-are-the-limits-of-type-checking-and-type-systems](http://stackoverflow.com/questions/1251791/what-are-the-limits-of-type-checking-and-type-systems) – nawfal Jul 08 '14 at 10:13

8 Answers8

7

Arrays are broken.

  Object[] foo = new String[1];
  foo[0] = new Integer(4);

Gives you java.lang.ArrayStoreException

You deal with them with caution.

Nullability is another big issue. NullPointerExceptions jump at your face everywhere. You really can't do anything about them except switch language, or use conventions of avoiding them as much as possible (initialize fields properly, etc).

More generally, the Java's/C#'s type systems are not very expressive. The most important thing Haskell can give you is that with its types you can enforce that functions don't have side effects. Having a compile time proof that parts of programs are just expressions that are evaluated makes programs much more reliable, composable, and easier to reason about. (Ignore the fact, that implementations of Haskell give you ways to bypass that).

Compare that to Java, where calling a method can do almost anything!

Also Haskell has pattern matching, which gives you different way of creating programs; you have data on which functions operate, often recursively. In pattern matching you destruct data to see of what kind it is, and behave according to it. e.g. You have a list, which is either empty, or head and tail. If you want to calculate the length, you define a function that says: if list is empty, length = 0, otherwise length = 1 + length(tail).

If you really like to learn more, there's two excellent online sources:

Learn you a Haskell and Real World Haskell

egaga
  • 21,042
  • 10
  • 46
  • 60
  • I'm not sure I understand the example. foo contains a string array, so trying to set foo[0] to an integer should fail - isn't that the point of a type system? – James Orr May 19 '09 at 18:57
  • 11
    No. The point of a type system is that it shouldn't compile. – mqp May 19 '09 at 19:02
4

I dislike the fact that there is a differentiation between primitive (native) types (int, boolean, double) and their corresponding class-wrappers (Integer, Boolean, Double) in Java.

This is often quite annoying especially when writing generic code. Native types can't be genericized, you must instantiate a wrapper instead. Generics should make your code more abstract and easier reusable, but in Java they bring restrictions with obviously no reasons.

private static <T> T First(T arg[]) {
    return arg[0];
}

public static void main(String[] args) {        
    int x[] = {1, 2, 3};
    Integer y[] = {3, 4, 5};

    First(x); // Wrong
    First(y); // Fine
}

In .NET there are no such problems even though there are separate value and reference types, because they strictly realized "everything is an object".

nawfal
  • 70,104
  • 56
  • 326
  • 368
Dario
  • 48,658
  • 8
  • 97
  • 130
3

this question about generics shows the deficiencies of the java type system's expressiveness
Higher-kinded generics in Java

Community
  • 1
  • 1
Chii
  • 14,540
  • 3
  • 37
  • 44
2

A fundamental weakness in the Java/.net type system is that it has no declarative means of specifying how an object's state relates to the contents of its reference-type fields, nor of specifying what a method is allowed to persist reference-type parameters. Although in some sense it's nice for the runtime to be able to use a field Foo of one type ICollection<integer> to mean many different things, it's not possible for the type system to provide real support for things like immutability, equivalency testing, cloning, or any other such features without knowing whether Foo represents:

  1. A read-only reference to a collection which nothing will ever mutate; the class may freely share such reference with outside code, without affecting its semantics. The reference encapsulates only immutable state, and likely does not encapsulate identity.
  2. A writable reference to a collection whose type is mutable, but which nothing will ever actually mutate; the class may only share such references with code that can be trusted not to mutate it. As above, the reference encapsulates only immutable state, and likely does not encapsulate identity.
  3. The only reference anywhere in the universe to a collection which it mutates. The reference would encapsulate mutable state, but would not encapsulate identity (replacing the collection with another holding the same items would not change the state of the enclosing object).
  4. A reference to a collection which it mutates, and whose contents it considers to be its own, but to which outside code holds references which it expects to be attached to `Foo`'s current state. The reference would encapsulate both identity and mutable state.
  5. A reference to a mutable collection owned by some other object, which it expects to be attached to that other object's state (e.g. if the object holding `Foo` is supposed to display the contents of some other collection). That reference would encapsulate identity, but would not encapsulate mutable state.

Suppose one wants to copy the state of the object that contains Foo to a new, detached, object. If Foo represents #1 or #2, one may store in the new object either a copy of the reference in Foo, or a reference to a new object holding the same data; copying the reference would be faster, but both operations would be correct. If Foo represents #3, a correct detached copy must hold a reference to a new detached object whose state is copied from the original. If Foo represents #5, a correct detached copy must hold a copy of the original reference--it must NOT hold reference to a new detached object. And if Foo represents #4, the state of the object containing it cannot be copied in isolation; it might be possible to copy a bunch of interconnected objects to yield a new bunch whose state is equivalent to the original, but it would not be possible to copy the state of objects individually.

While it won't be possible for a type system to specify declaratively all of the possible relationships that can exist among objects and what should be done about them, it should be possible for a type system and framework to correctly generate code to produce semantically-correct equivalence tests, cloning methods, smoothly inter-operable mutable, immutable, and "readable" types, etc. in most cases, if it knew which fields encapsulate identity, mutable state, both, or neither. Additionally, it should be possible for a framework to minimize defensive copying and wrapping in circumstances where it could ensure that the passed references would not be given to anything that would mutate them.

supercat
  • 77,689
  • 9
  • 166
  • 211
2

I don't like the fact that classes are not first-class objects, and you can't do fancy things such as having a static method be part of an interface.

pgb
  • 24,813
  • 12
  • 83
  • 113
  • Small point: with C# 3 you can add extension methods to interfaces, which amounts to the same thing. – James Orr May 19 '09 at 18:53
  • @Barry that's incorrect, you still need to have an instance of the interface to be able to call an extension method. A static method on an interface would allow you to call the method regardless or whether or not you had an instance. – Joseph May 19 '09 at 19:00
  • Since Java 8 you can have static methods in interfaces. – Lii Jan 05 '20 at 22:28
0

(Re: C# specifically.)

I would love tagged unions.

Ditto on first-class objects for classes, methods, properties, etc.

Although I've never used them, Python has type classes that basically are the types that represent classes and how they behave.

Non-nullable reference types so null-checks are not needed. It was originally considered for C# but was discarded. (There is a stack overflow question on this.)

Covariance so I can cast a List<string> to a List<object>.

Community
  • 1
  • 1
Colin Burnett
  • 11,150
  • 6
  • 31
  • 40
  • Non-nullable reference types would be nice! Spec#, a C#-extension, includes them. Covariance will exist in the next C#-version. – Dario May 19 '09 at 19:08
  • The .NET System.Type class represents types. What makes the Python type first-class, and the .NET Type not? – James Orr May 19 '09 at 20:13
  • @Barry. System.Type is first class but it's not the class (that is *key*). I cannot create "public class Foo {}" and later do "Foo.MyFunMethod = funmethod" to add a new method (either before or after compiling). Perhaps prototyping in Javascript is more familiar to you? – Colin Burnett May 19 '09 at 21:58
  • Colin, I see what you're getting at. So mutability is a condition for first-class-ness. – James Orr May 19 '09 at 23:37
  • Mutability isn't a requisite for first-classness but it can be useful/helpful. As another example, you cannot create new methods at run-time in .NET (lambdas & such are syntactical sugar that translate to static methods). In Python, I can create new methods at run-time (they are more than just pointers/references) just like creating a new instance of a class. Python methods and classes have intrinsic fields themselves because they are objects. You really should pick up some Smalltalk, Python, Ruby, etc. to see it in action. – Colin Burnett May 20 '09 at 01:59
  • Thanks for the info, it's appreciated! – James Orr May 20 '09 at 14:47
0

This is minor, but for the current versions of Java and C# declaring objects breaks the DRY principle:

Object foo = new Object; 
Int x = new Int; 
Rob Allen
  • 17,381
  • 5
  • 52
  • 70
  • 1
    Albeit with C# you can just use "var x = new Whatever();" and the compiler will do the right thing for you – Camilo Díaz Repka May 19 '09 at 19:02
  • It has gotten better and with C# 3 you can use local type inference (var x = 0; instead of Int x = 0;) but we aren't in Python/Ruby territory yet – Rob Allen May 19 '09 at 19:08
-1

None of them have meta-programming facilities like say that old darn C++ dog has.

Using "using" duplication and lack of typedef is one example that violates DRY and can even cause user-induced 'aliasing' errors and more. Java 'templates' isn't even worth mentioning..

rama-jka toti
  • 1,404
  • 10
  • 16