Skip to main content

Nullable Types (like in C# 2.0)

24 replies [Last post]
fuerte
Offline
Joined: 2004-11-22

Please see this first:
http://msdn.microsoft.com/vcsharp/2005/overview/language/nullabletypes/

This is a great new feature, which makes database programming much easier. I think that is essential, as the article says.

As a side note, I wish that Java eventually gets full support for value types like int/Integer and string/String. int should be a synonym for Integer and string synonym for String. Comparing strings with == should compare the value, not the object reference. Likewise, comparing Integers with == and != should always compare the value, not the reference.

And I wish that Java had int? type in the future.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
hlovatt
Offline
Joined: 2003-11-18

I would suggest the C++ like syntax of:
[code]
ArrayList< Integer > v( 10 );
[/code]
This is consistant with method argument declarations, doesn't require a new keyword (def), is short, and is compatable with final.

However, I can see why Sun haven't done this:

1. The gain is very small, my IDE pretty much fills in the right hand side of a declaration for me

2. Having two syntax for the same thing is confusing to newbies.

hlovatt
Offline
Joined: 2003-11-18

> Instead could we do this:
[pre]
> 01: try (Connection conn = DriverManager (...)) {
> 02: try (PreparedStatement query = conn.prepareStatement (...)) {
> 03: try (ResultSet result = query.executeQuery()) {
> 04: //do stuff
> 05: }
> 06: }
> 07: }
[/pre]
This is a good suggestion, but has a couple of problems:

1. What if you want a finally block, does it come before or after the generated one

2. What happens if someone passes the resource to another method, that caches the resource, and then the resource is closed

How about going even further:

1. Define an interface called Resource that has a close() method

2. If a class implements this interface then the compiler automatically codes the try/finally block when the constructor is called (finally is when the variable goes out of scope)

3. You can then manually add a try/finally block either around the declaration or around just the code using the resource and this way control the order of finally clauses

4. You can control scope with {} if you wish

5. Ban passing a resource to a method, [i]other than a method in the same package as the resource,[/i] see above for why passing a resource may be a problem

6. Something along these lines was suggested by Neal Gafter - see http://forums.java.net/jive/thread.jspa?threadID=367&start=0&tstart=0

Using my proposed Resource interface the above example becomes:
[code]
Connection conn = DriverManager( ... );
PreparedStatement query = conn.prepareStatement( ... );
ResultSet result = query.executeQuery()
// do stuff
[/code]

sjasja
Offline
Joined: 2004-08-15

I played around with the idea of a similar trick. Here's my version:
[code]
Connection conn = DriverManager.getConnection(...)
finally Closer.close(conn);
PreparedStatement query = conn.prepareStatement(...)
finally Closer.close(query);
ResultSet result = query.executeQuery()
finally Closer.close(result);
//do stuff
[/code]
That has the trouble that I can't think of a clean way to add a catch block if I suddenly want one.

fuerte
Offline
Joined: 2004-11-22

Also the original "try () {}" extension has some unresolved questions: What if there is "finally" as well? Should the automatic cleanup happen in the beginning of it or in the end? If in the beginning, then you can't access the object anymore, but if in the end, then it might not be closed properly, if there is a problem in finally block.

subanark
Offline
Joined: 2004-11-26

If you want to shorten the syntax do it on the left side, not the right, which is what groovy does.

E.g.

def v = new ArrayList(10);

This way you can have arguments in the constructor, or it can be the result of a method instead of a constructor. This format is, v takes on the type it is assigned.

fuerte
Offline
Joined: 2004-11-22

> If you want to shorten the syntax do it on the left
> side, not the right, which is what groovy does.
>
> E.g.
>
> def v = new ArrayList(10);
>
> This way you can have arguments in the constructor,
> or it can be the result of a method instead of a
> constructor. This format is, v takes on the type it
> is assigned.

But doesn't it mean that the type of v is somewhat obscure? I like the strict type checking of Java.

Also the following would be possible with my suggestion:

ArrayList v = new(10);

rogerhernandez
Offline
Joined: 2005-02-23

Also, in some cases the optimizer can do a better job of inlining functions if it knows that an object is the actual collection class instead of a base interface.

I am have been doing lots of JDBC programming in the last few days and one simple change that would help out a lot is a better way of making sure that resources are released as soon as they are no longer needed.

Normally you have to write:
[pre]
01: Connection conn = DriverManager.getConnection (...)
02: try {
03: PreparedStatement query = conn.prepareStatement (...);
04: try {
05: ResultSet result = query.executeQuery ();
06: try {
07: //do stuff
08: }
09: finally {
10: result.close ();
11: }
12: }
13: finally {
14: query.close ();
15: }
16: }
17: finally {
18: conn.close ();
19: }
[/pre]
Only the lines 1, 3, 5 and 7 are real code, everything else is resource clean-up code.

Instead could we do this:
[pre]
01: try (Connection conn = DriverManager (...)) {
02: try (PreparedStatement query = conn.prepareStatement (...)) {
03: try (ResultSet result = query.executeQuery ()) {
04: //do stuff
05: }
06: }
07: }
[/pre]
No new keywords, very simple change to the grammar, and 19 lines went down to 7 lines. Much easier to see what the code is really doing when you are not bogged down in the clean-up cruft.

An object allocated inside the try ( ) construct must implement a Closeable or Releaseable interface and the compiler will call the appropriate .close or .release function exactly as if the code had been:
[pre]
Closeable res = acquireResource ();
try
{
//do stuff
}
finally
{
res.close ();
}
[/pre]
Saves a whole bunch of typing, and no new keywords. What do you think?

And please, no "You infidel, go use Ruby/C#/C++/Assembly if you like it so much." or "You young whippersnappers too lasy to type a few lines!" or "Syntatic sugar! SYNTATIC SUGAR!11!1".

Let's stick to the technical pros and cons of the suggestion.

fuerte
Offline
Joined: 2004-11-22

> Instead could we do this:
> [pre]
> 01: try (Connection conn = DriverManager (...)) {
> 02: try (PreparedStatement query =
> conn.prepareStatement (...)) {
> 03: try (ResultSet result = query.executeQuery
> ()) {
> 04: //do stuff
> 05: }
> 06: }
> 07: }
> [/pre]
> No new keywords, very simple change to the grammar,
> and 19 lines went down to 7 lines. Much easier to
> see what the code is really doing when you are not
> bogged down in the clean-up cruft.

This is better than C# using(), excellent! :-)

dog
Offline
Joined: 2003-08-22

"C# already has a big edge in database programming, because it has multi-line string literals with @"."

I personally like multi-line Strings like php's HEREDOC.. Can be very useful.

That being said.. some of us moved to Java (from C++) because we were tired of the feature creep (that slows down dev time) and welcomed rich libraries.

We don't want Java to be the language with all the features (let Perl and C++ be that). We just want a language with a simple and orthogonal syntax.

Languages aren't necessarily better because they have more features.

jwenting
Offline
Joined: 2003-12-02

well said dog. If the kiddos want feature XXXXXX because it's in language YYYYYY they should use language YYYYYY instead of screaming that Java is basically flawed until that feature is added to it.

subanark
Offline
Joined: 2004-11-26

The @ may help a bit with String literals, but not that much. You don't add that much clutter:
[code]
String s = "Line 1\n" +
"Line 2";
[/code]

Java strives on being simple and clear.
I am sure that if the java developers could have designed the language differently in some ways they would have, but a balance needs to be kept between readability, compadibility, simplicity, power, and speed.

pholthuizen
Offline
Joined: 2005-02-12

> Except that in Java the following fails:
>
> Integer i = new Integer(123456);
> Integer j = new Integer(123456);
> if (i == j) print("huh? fails!")

This problem is only there when you initialize with new Integer(###).

Integer i = 123456;
Integer j = 123456;
if (i == j) print("equality")

It remains a design flaw though...

subanark
Offline
Joined: 2004-11-26

I really don't see it as a design flaw.

If you want unique instances that only contains an int, then creating a new Integer works just fine.

Unless there is a need avoid declaring types of Integer, instead just declare them as int.
E.g.
[code]
List list1 = new ArrayList();
list1.add(1);
list1.add(3);
list1.add(4);
List list2 = new ArrayList();
list2.add(2);
list2.add(8);
list2.add(-2);

int total1 = 0;
for(int v:list1)
total1 += v;
int total2 = 0;
for(int v:list2)
total2 += v;
System.out.println("List one has the same sum as list 2:"+(total1 == total2));
[/code]

This works fine. The only thing I would suggest is a lint option.

fuerte
Offline
Joined: 2004-11-22

By the way, I would write the above code as follows:
[code]
ArrayList list1 = new;
list1.add(1);
list1.add(3);
list1.add(4);
ArrayList list2 = new;
list2.add(2);
list2.add(8);
list2.add(-2);

int total1 = 0;
for(v:list1)
total1 += v;
int total2 = 0;
for(v:list2)
total2 += v;
System.out.println("List one has the same sum as list 2:"+(total1 == total2));
[/code]
Spot the differences? It should be possible to remove redundant type declarations when the compiler already knows the type:

ArrayList list1 = new;
for(v:list1)

fred33
Offline
Joined: 2005-08-16

> ArrayList list1 = new;
> for(v:list1)

This doesn't even make sense, what is v meant to be? The enhanced for loop already hides some detail, lets not make it worse. I do agree that sometimes some syntactic sugar to remove some typing like the "new" idea above is useful, but ultimately makes it harder to read some code. And by the way, if c# has the features, semantics, capabilities and satisfactory performance you require, why are you using Java? There are more languages out there than I can name and if language X provides better support for the task you are trying to complete, then you should be using it. I'm wondering how long it will be before people demand javax.defragment and javax.firewall packages be created so people can write cross platform disk defraggers and stuff.

fuerte
Offline
Joined: 2004-11-22

> > ArrayList list1 = new;
> > for(v:list1)
>
> This doesn't even make sense, what is v meant to be?

v is meant to be a new variable named "v" of correct type that can iterate the iterator that is defined after :, so the type in this case should be Integer. The compiler already knows the correct type, so the programmer should not be forced to repeat it. This would work, because you have to create a new variable here always.

> The enhanced for loop already hides some detail, lets
> not make it worse.

It just would be easier. As you said, the iterator for loop hides details which is good, so that you don't have to write the iterator loop yourself.

> I do agree that sometimes some
> syntactic sugar to remove some typing like the "new"
> idea above is useful, but ultimately makes it harder
> to read some code.

Great that you agree on this one at least! :-)

Message was edited by: fuerte

tsinger
Offline
Joined: 2003-06-10

> v is meant to be a new variable named "v" of correct
> type that can iterate the iterator that is defined
> after :, so the type in this case should be Integer.
> The compiler already knows the correct type, so the
> programmer should not be forced to repeat it.

It is strange, that you are obviously too lazy to type "Integer v", but write "ArrayList" instead of "List". Just a small thought.

Have a nice weekend,
Tom

fuerte
Offline
Joined: 2004-11-22

> > v is meant to be a new variable named "v" of
> correct
> > type that can iterate the iterator that is defined
> > after :, so the type in this case should be
> Integer.
> > The compiler already knows the correct type, so
> the
> > programmer should not be forced to repeat it.
>
> It is strange, that you are obviously too lazy to
> type "Integer v", but write "ArrayList"
> instead of "List". Just a small thought.

You missed the point, I am lazy enough to write

ArrayListlist1 = new;

instead of

Listlist1 = new ArrayList();

elizas
Offline
Joined: 2010-03-19

The nullable type can represent a normal or regular set of values for its value type including the null value.

If we take an example of bool type, then Nullable can contain set of values like true or false or null.So, assigning null value to bool is useful when we are dealing with database in which the Boolean field may store value like true or false or it may be sometimes undefined.

Nullable Types are instances of System.Nullable struct.

Declaration:
A nullable type can be declared similar to normal variable but with ? modifier at the end of keyword.For example,
int? number = null;
Here ? denotes that the object is a Nullable object of that specific datatype(here it is int).

Alternative way of declaring Nullable type is,
Nullable number = null;

sjasja
Offline
Joined: 2004-08-15

Is there an essential difference between "int?" in C# and "Integer" in Java? The C# example:
[code]
int? x = 123;
int? y = null;
if (x.HasValue) Console.WriteLine(x.Value);
if (y.HasValue) Console.WriteLine(y.Value);
[/code]
trivially translates to Java's:
[code]
Integer x = 123;
Integer y = null;
if (x != null) System.out.println(x);
if (y != null) System.out.println(y);
[/code]
Where's the beef?

> int should be a synonym for Integer

I surely hope not. An object necessarily needs a pointer (so it can be null) and the data itself, usually also a "vtable" pointer (aka a pointer to the object's class). That makes Integer and "int?" at least two to five times as big as an int (depending on whether you have 32-bit or 64-bit pointers.)

Also e.g. adding two integers would require dereferencing to get to the actual values, instead of just a simple "add" machine instruction. The simplest things like incrementing a loop variable would become several times slower.

That's a pretty heavy penalty to pay for every single int in every single program.

If you want a slow, bloated language where everything is an object for aesthetical/theoretical/academic reasons, try googling for one. I'm sure there are several of those already.

fuerte
Offline
Joined: 2004-11-22

> Is there an essential difference between "int?" in C#
> and "Integer" in Java? The C# example:
> [code]
> int? x = 123;
> int? y = null;
> if (x.HasValue) Console.WriteLine(x.Value);
> if (y.HasValue) Console.WriteLine(y.Value);
> [/code]
> trivially translates to Java's:
> [code]
> Integer x = 123;
> Integer y = null;
> if (x != null) System.out.println(x);
> if (y != null) System.out.println(y);
> [/code]
> Where's the beef?

Try running x + y.

> > int should be a synonym for Integer
>
> I surely hope not. An object necessarily needs a
> pointer (so it can be null) and the data itself,
> usually also a "vtable" pointer (aka a pointer to the
> object's class). That makes Integer and "int?" at
> least two to five times as big as an int (depending
> on whether you have 32-bit or 64-bit pointers.)

Perhaps I should have said that Integer should be a synonym for int (and vice versa). I mean that the compiler (and hotspot compiler) will take care of the performance.

> Also e.g. adding two integers would require
> dereferencing to get to the actual values, instead of
> just a simple "add" machine instruction. The simplest
> things like incrementing a loop variable would become
> several times slower.

No, there would be no difference.

> That's a pretty heavy penalty to pay for every single
> int in every single program.

Integer i = 1;
Integer j = 2;
Integer k = i + j;
printf("%d", k);

is exactly the same as

int i = 1;
int j = 2;
int k = i + j;
printf("%d", k);

Except that in Java the following fails:

Integer i = new Integer(123456);
Integer j = new Integer(123456);
if (i >= j) print("true");
if (i <= j) print("of course");
if (i == j) print("huh? fails!")

> If you want a slow, bloated language where everything
> is an object for aesthetical/theoretical/academic
> reasons, try googling for one. I'm sure there are
> several of those already.

Java is such, because there are no primitive types like C# int and string.

jwenting
Offline
Joined: 2003-12-02

> > Is there an essential difference between "int?" in
> C#
> > and "Integer" in Java? The C# example:
> > [code]
> > int? x = 123;
> > int? y = null;
> > if (x.HasValue) Console.WriteLine(x.Value);
> > if (y.HasValue) Console.WriteLine(y.Value);
> > [/code]
> > trivially translates to Java's:
> > [code]
> > Integer x = 123;
> > Integer y = null;
> > if (x != null) System.out.println(x);
> > if (y != null) System.out.println(y);
> > [/code]
> > Where's the beef?
>
> Try running x + y.
>
And why the heck should that result in anything BUT an NPE?
null != 0, learn that, understand it, live by it.
You're stuck in thinking that Java == C++ and that therefore NULL == 0, but null != NULL so null != 0.

> Perhaps I should have said that Integer should be a
> synonym for int (and vice versa). I mean that the
> compiler (and hotspot compiler) will take care of the
> performance.
>
autoboxing gives you that for all practical purposes.
No need to do anything else like your deranged idea of making null identical to 0.

> Java is such, because there are no primitive types
> like C# int and string.

uh, there IS int in Java.
String is a class, that's a language definition in an OO environment.
I'd sooner get rid of primitives than redefine everything as a primitive (why stop with String, I use a lot of Lists and Maps which would be cute as primitives as well, saves a few constructor calls...).

fuerte
Offline
Joined: 2004-11-22

> > > Is there an essential difference between "int?"
> in
> > C#
> > > and "Integer" in Java? The C# example:
> > > [code]
> > > int? x = 123;
> > > int? y = null;
> > > if (x.HasValue) Console.WriteLine(x.Value);
> > > if (y.HasValue) Console.WriteLine(y.Value);
> > > [/code]
> > > trivially translates to Java's:
> > > [code]
> > > Integer x = 123;
> > > Integer y = null;
> > > if (x != null) System.out.println(x);
> > > if (y != null) System.out.println(y);
> > > [/code]
> > > Where's the beef?
> >
> > Try running x + y.
> >
> And why the heck should that result in anything BUT
> an NPE?
> null != 0, learn that, understand it, live by it.
> You're stuck in thinking that Java == C++ and that
> therefore NULL == 0, but null != NULL so null != 0.

No, in SQL the result is NULL. That is the point. You don't get an exception but the null value propagates.

> > Perhaps I should have said that Integer should be
> a
> > synonym for int (and vice versa). I mean that the
> > compiler (and hotspot compiler) will take care of
> the
> > performance.
> >
> autoboxing gives you that for all practical
> purposes.
> No need to do anything else like your deranged idea
> of making null identical to 0.

Well the idea is that autoboxing should be invisible... that's why int = Integer and we could have int.parse instead of Integer.parseInt.

> > Java is such, because there are no primitive types
> > like C# int and string.
>
> uh, there IS int in Java.
> String is a class, that's a language definition in an
> OO environment.
> I'd sooner get rid of primitives than redefine
> everything as a primitive (why stop with String, I
> use a lot of Lists and Maps which would be cute as
> primitives as well, saves a few constructor calls...).

In C# int is both a primitive and a class. Java int and Integer makes it unnecessary complicated. C# is cleaner.

On the other hand, because C# int can't be null, it makes it more difficult for database programming. int? fixes that, and gives more bonuses, like null propagation, and handy operators like ??.

C# already has a big edge in database programming, because it has multi-line string literals with @".

Java autoboxing is currently broken, because new Integer(123456) != new Integer(123456). Primitive types should always compare values...

sjasja
Offline
Joined: 2004-08-15

>> Where's the beef?
>
> Try running x + y.

Okay:
[code]
public class Test
{
public static void main(String args[])
{
Integer x = 123;
Integer y = null;
if (x != null) System.out.println(x);
if (y != null) System.out.println(y);
System.out.println(x + y);
}
}
[/code]
Compiles fine, runs fine, produces a NullPointerException as it should.

> No, in SQL the result is NULL. That is the point.
> You don't get an exception but the null value propagates.

Yes, that's what happens in SQL. Which is kind of a silly thing to happen; it hides programming errors in a nasty way.

Java is not SQL.

If you insist on masking programming errors in Java, try this:
[code]
public static Integer add(Integer x, Integer y)
{
if (x == null || y == null)
return null;
return x + y;
}
[/code]
>> Also e.g. adding two integers would require
>> dereferencing to get to the actual values, instead of
>> just a simple "add" machine instruction. The simplest
>> things like incrementing a loop variable would become
>> several times slower.
>
> No, there would be no difference.

Yes, there is a difference between Integer and int. Integer, being an object, requires that there is a pointer which points to the actual data. That pointer can be null or non-null, giving you the "nullable" semantics you want. Getting at the data requires dereferencing the pointer.

There is a speed and a time cost to Integer compared to int.

>> If you want a slow, bloated language where everything
>> is an object for aesthetical/theoretical/academic
>> reasons, try googling for one. I'm sure there are
>> several of those already.
>
> Java is such, because there are no primitive types
> like C# int and string.

Wow. I recommend you read a Java basics book; any one of them should set you straight.

> int? fixes that, and gives more bonuses, like null
> propagation, and handy operators like ??.

Try writing a couple of static helper functions and you should be fine. I still think null propagation in arithmetic is a really bad idea, but each to his own.

> C# already has a big edge in database programming,
> because it has multi-line string literals with @".

That is a big edge? How to type a string literal? Wow.

> Java autoboxing is currently broken, because
> new Integer(123456) != new Integer(123456).

There are millions of programmers who have learned the difference between == and .equals(). It's not that difficult to learn.