Has Java become too complicated?

  • Thread starter frustratedprogrammer
  • Start date
M

Mike Schilling

Lew said:
It may have been simply to simplify the implementation of Java. Inner
classes are tied to the enclosing instance. Making static members visible
only to instances created within the enclosing object, but not to other
objects of the enclosing class, would have been difficult to implement

I don't know what you mean by "instances created within the enclosing
object". Static fields of an inner class would, logically, act exactly like
static fields of any other class: accessible as fully-qualified name to any
code that is allowed to access them, and as simple names within the class
itself. (For anonymous and local classes, which have no fully-qualified
names, only visible within the class.) This wouldn't be difficult to
implement; in fact, I suspect all that would be necessary is removing the
current checks that make non-constant static members illegal.

The current restrictions limit the complexity of the code run while
initializing an inner class; I don't see any particular need for that.
 
L

Lew

Mike said:
I don't know what you mean by "instances created within the enclosing
object". Static fields of an inner class would, logically, act exactly like
static fields of any other class: accessible as fully-qualified name to any
code that is allowed to access them, and as simple names within the class
itself. (For anonymous and local classes, which have no fully-qualified
names, only visible within the class.) This wouldn't be difficult to
implement; in fact, I suspect all that would be necessary is removing the
current checks that make non-constant static members illegal.

Not true. Inner classes belong to an instance of the enclosing class.

So, for example, (untested)

public class Foo
{
class Bar
{
}

public static void main( String [] args )
{
Foo a;
Foo b;
}
}

In this example, a.Bar and b.Bar are /different/ classes. They cannot share
static non-constant members.

- Lew
 
M

Mike Schilling

Lew said:
Not true. Inner classes belong to an instance of the enclosing class.

No, inner class *instances* have an enclosing *instance*.
So, for example, (untested)

public class Foo
{
class Bar
{
}

public static void main( String [] args )
{
Foo a;
Foo b;
}
}

In this example, a.Bar and b.Bar are /different/ classes. They cannot
share static non-constant members.

There's only one class; it's called Foo$Bar. Try running the following
program:

public class Foo
{
class Bar
{
}

public static void main( String [] args )
{
Foo a = new Foo();
Foo b = new Foo();

Bar ab = a.new Bar();
Bar bb = b.new Bar();

System.out.println(ab.getClass());
System.out.println(bb.getClass());
System.out.println(ab.getClass() == bb.getClass());

}
}
 
L

Lew

Mike said:
No, inner class *instances* have an enclosing *instance*.
So, for example, (untested)

public class Foo
{
class Bar
{
}

public static void main( String [] args )
{
Foo a;
Foo b;
}
}

In this example, a.Bar and b.Bar are /different/ classes. They cannot
share static non-constant members.
There's only one class; it's called Foo$Bar. Try running the following
program:

Interesting, because in the section (8.1.3) on inner classes the JLS states

"So, for example, the class Local above has an enclosing instance of class
Outer. "

So while the actual implementation may use a single class definition, it has
to act as if each instance has its own Local class.

- Lew
 
M

Mike Schilling

Lew said:
Mike said:
No, inner class *instances* have an enclosing *instance*.
So, for example, (untested)

public class Foo
{
class Bar
{
}

public static void main( String [] args )
{
Foo a;
Foo b;
}
}

In this example, a.Bar and b.Bar are /different/ classes. They cannot
share static non-constant members.
There's only one class; it's called Foo$Bar. Try running the following
program:

Interesting, because in the section (8.1.3) on inner classes the JLS
states

"So, for example, the class Local above has an enclosing instance of class
Outer. "

You're being misled by sloppy wording. It should say "Every instance of
class Local ...". Note that the definitions at the start of 8.1.3 include
the definition of an enclosing class of an inner class and the definition of
an enclosing instance of an inner class instance, but not the definition of
an enclosing instance of an inner class, becasue there is no such thing.

Note also the following paragraph, which is more careful with its language:

"Here, every instance of WithDeepNesting.Nested.DeeplyNested has an
enclosing instance of class WithDeepNesting.Nested (its immediately
enclosing instance) and an enclosing instance of class WithDeepNesting (its
2nd lexically enclosing instance)"
 
L

Lew

Mike said:
No, inner class *instances* have an enclosing *instance*.
So, for example, (untested)

public class Foo
{
class Bar
{
}

public static void main( String [] args )
{
Foo a;
Foo b;
}
}

In this example, a.Bar and b.Bar are /different/ classes. They cannot
share static non-constant members.
There's only one class; it's called Foo$Bar. Try running the following
program:

Interesting, because in the section (8.1.3) on inner classes the JLS states

"So, for example, the class Local above has an enclosing instance of
class Outer. "

So while the actual implementation may use a single class definition, it
has to act as if each instance has its own Local class.

Since Foo$Bar is byte code, it is not a reliable indicator of what the Java
language is. That is why I went to the JLS for my insight.

The Java language is what's enforced by the compiler; Foo$Bar is what the
compiler produces after the syntax is approved, and is no longer Java.

Not only is Foo$Bar not associated with any instance, Foo$Bar isn't even
nested; it's implemented as a top-level class named Foo$Bar. Surely you cannot
conclude from this that there are no such things as nested classes in Java.

But let's set aside what I said and talk about inner instances belonging to
outer instances. Define static, non-final X x inside Bar.

Assume Foo variables a and b reference different objects. a.x would belong to
a, and b.x would belong to b, by the rules of inner classes. But we said x is
static in Bar, so x does not belong to a or b. The inner-classness wants the
xes to be different but the staticness wants them to be the same. I can
imagine Gosling or whomever thinking that this is tricky and weird, and
somehow contrary to the notion of inner class things belong to an outer class
instance.

Besides, there is that little clause in the JLS that it would violate.

This isn't a defense of the syntax exactly. I am speculating on how it makes
sense to deny such static members given that they are denied, not trying to
say it's better than the alternatives.

So while it isn't maybe precisely true, although I think it is, that inner
classes belong to enclosing instances in Java, it sure is set up in the
language that you can think of it that way with impunity.

<http://www.javaworld.com/javaworld/javatips/jw-javatip75.html>
"nested classes are associated with the enclosing class itself, whereas inner
classes are associated with an object of the enclosing class."

<http://www.onjava.com/pub/a/onjava/excerpt/HardcoreJava_chap06/index2.html>
(Simmons, /Hardcore Java/, O'Reilly)
"To be an inner class, a class has to have instance scope."
and
"Formally, it can be said that an inner class is instance-scoped and a static
nested class is class-scoped. "

<http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html>
(The Sun Java Tutorial)
"an inner class is associated with an instance of its enclosing class"

- Lew
 
L

Lew

Mike said:
You're being misled by sloppy wording. It should say "Every instance of
class Local ...".

Now you're rewriting the JLS?

My other post shows how even Sun themselves speak of an inner class
associating with an instance.

- Lew
 
M

Mike Schilling

Lew said:
Inner classes belong to an instance of the enclosing class.

Mike said:
No, inner class *instances* have an enclosing *instance*.
So, for example, (untested)

public class Foo
{
class Bar
{
}

public static void main( String [] args )
{
Foo a;
Foo b;
}
}

In this example, a.Bar and b.Bar are /different/ classes. They cannot
share static non-constant members.
There's only one class; it's called Foo$Bar. Try running the following
program:

Interesting, because in the section (8.1.3) on inner classes the JLS
states

"So, for example, the class Local above has an enclosing instance of
class Outer. "

So while the actual implementation may use a single class definition, it
has to act as if each instance has its own Local class.

Since Foo$Bar is byte code, it is not a reliable indicator of what the
Java language is. That is why I went to the JLS for my insight.

The Java language is what's enforced by the compiler; Foo$Bar is what the
compiler produces after the syntax is approved, and is no longer Java.

Not only is Foo$Bar not associated with any instance, Foo$Bar isn't even
nested; it's implemented as a top-level class named Foo$Bar. Surely you
cannot conclude from this that there are no such things as nested classes
in Java.

But let's set aside what I said and talk about inner instances belonging
to outer instances. Define static, non-final X x inside Bar.

Assume Foo variables a and b reference different objects. a.x would belong
to a, and b.x would belong to b, by the rules of inner classes. But we
said x is static in Bar, so x does not belong to a or b. The
inner-classness wants the xes to be different but the staticness wants
them to be the same. I can imagine Gosling or whomever thinking that this
is tricky and weird, and somehow contrary to the notion of inner class
things belong to an outer class instance.

Besides, there is that little clause in the JLS that it would violate.

This isn't a defense of the syntax exactly. I am speculating on how it
makes sense to deny such static members given that they are denied, not
trying to say it's better than the alternatives.

So while it isn't maybe precisely true, although I think it is, that inner
classes belong to enclosing instances in Java, it sure is set up in the
language that you can think of it that way with impunity.

<http://www.javaworld.com/javaworld/javatips/jw-javatip75.html>
"nested classes are associated with the enclosing class itself, whereas
inner classes are associated with an object of the enclosing class."

Again, sloppy wording.
<http://www.onjava.com/pub/a/onjava/excerpt/HardcoreJava_chap06/index2.html>
(Simmons, /Hardcore Java/, O'Reilly)
"To be an inner class, a class has to have instance scope."
and
"Formally, it can be said that an inner class is instance-scoped and a
static nested class is class-scoped. "

Scoping is an entirely different issue. It would be equally true to say
that static methods are class-scoped and instance methods are
instance-scoped.
<http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html>
(The Sun Java Tutorial)
"an inner class is associated with an instance of its enclosing class"

More sloppy wording.

One more question: In the following fragment:

class Foo
{
class Bar{ ...}

static Bar b;
}

What type is b?
 
L

Lew

Where it needs it, yes.

My, my.

You see, I use the JLS as the authority on the Java language. I just don't
know how I could understand the language if I could just throw away parts of
the specification for it. I mean, how can one tell where it needs it, given
that the JLS defines the language?

Especially in light of the many other sources including the Sun tutorial, that
use the verbiage that an inner class is associated with an outer instance.

But if you feel you can define the language better than Sun and the JLS, I
sure don't know how we can have a meaningful discussion. I sort of have to
rest on those sources as the authority, and disputation of the JLS as prima
facie not tenable.

I thought I was doing a little forensics on the motivation for the banning of
non-final statics in inner classes, now I see we can't even agree on the
definition of the Java language. Based on authoritative sources, without
deconstruction or capricious rejection of parts of the JLS that I feel
"shouldn't" say what they actually do say, I will stick with thinking of inner
classes as being associated with outer class instances. Your way of describing
it really doesn't contradict that point of view anyway.

I really, really want to recommend that you not consider parts of the JLS as
wrong that way. It was very carefully written by a lot of people, and likely
says exactly what it intends to. Besides, by definition Java is what the JLS
says it is, so you fall into a weird solipsistic trap trying to second guess
the very defintion of the language, especially in this case where there is so
much supporting ancillary documentation.

- Lew
 
L

Lew

Mike said:
One more question: In the following fragment:

class Foo
{
class Bar{ ...}

static Bar b;

public static void main( String [] args )
{
Foo x = new Foo();
b = x.new Bar();
}
}

What type is b?

I see what you mean, but it still makes sense to say it the way the JLS and
Sun did, just not quite the way I thought. Let me explain.

I misspoke in my first statements when I said that the class was different for
each object - even as I said that I knew that class is always Foo.Bar. It is
the same class. So I see why one might think it is all right to relax the
inner class static variable rule that they must be final.

However, the JSL and Sun do not say that different instances have different
types, but that the class is associated with an instance. That is a runtime
phenomenon, "associated with", it looks like. So in the above snippet, b has
the class Bar that is associated with x. But unlike what I first said, the
type does not change. The association with a particular object changes.

Now I understand why you call their wording "sloppy". I think I get what they
mean, but it is not very understandable.

Now let me try to second-guess why they thought allowing non-final statics is
bad. It seems, perhaps, to break the association of these statics with outer
class objects, and the idea that static inner class variables could maybe need
access to outer class instance variables is just a mess. So they ducked the
whole issue by forbidding that kind of variable.

This kind of thinking would hold just as much under your way of describing
instances as being associated with outer instances - the question is whether
this would also apply to inner variables, and the question of access to outer
non-static variables remains, too. I think the designers just decided that it
wss better to stay out of the area then get caught up in the conflict with the
essential instanceness of inner classes with respect to outer ones.

I also can agree that Java could define non-final statics in inner classes if
the designers wanted it to. I have to wonder what other trouble that would
have caused that made them shy away from it. I find the consistent Sun
attitude, even if sloppy, that inner classes belong to outer instances to be a
strong forensic clue to the mindset that bans such statics.

- Lew
 
M

Mike Schilling

Lew said:
My, my.

You see, I use the JLS as the authority on the Java language. I just don't
know how I could understand the language if I could just throw away parts
of the specification for it. I mean, how can one tell where it needs it,
given that the JLS defines the language?

Then I suggest you not read JLS 3. It's full of obvious mistakes and typos
in the new material, especially where it discussing generics.
Especially in light of the many other sources including the Sun tutorial,
that use the verbiage that an inner class is associated with an outer
instance.

But if you feel you can define the language better than Sun and the JLS, I
sure don't know how we can have a meaningful discussion. I sort of have to
rest on those sources as the authority, and disputation of the JLS as
prima facie not tenable.

I thought I was doing a little forensics on the motivation for the banning
of non-final statics in inner classes, now I see we can't even agree on
the definition of the Java language. Based on authoritative sources,
without deconstruction or capricious rejection of parts of the JLS that I
feel "shouldn't" say what they actually do say, I will stick with thinking
of inner classes as being associated with outer class instances. Your way
of describing it really doesn't contradict that point of view anyway.

I really, really want to recommend that you not consider parts of the JLS
as wrong that way. It was very carefully written by a lot of people, and
likely says exactly what it intends to. Besides, by definition Java is
what the JLS says it is, so you fall into a weird solipsistic trap trying
to second guess the very defintion of the language, especially in this
case where there is so much supporting ancillary documentation.

Where one sentence in a section contradicts the rest of it, I feel free to
assume that sentence is in error. I don't see how I could reasonably do
otherwise.
 
M

Mike Schilling

Lew said:
Mike said:
One more question: In the following fragment:

class Foo
{
class Bar{ ...}

static Bar b;

public static void main( String [] args )
{
Foo x = new Foo();
b = x.new Bar();
}
}

What type is b?

I see what you mean, but it still makes sense to say it the way the JLS
and Sun did, just not quite the way I thought. Let me explain.

I misspoke in my first statements when I said that the class was different
for each object - even as I said that I knew that class is always Foo.Bar.
It is the same class. So I see why one might think it is all right to
relax the inner class static variable rule that they must be final.

However, the JSL and Sun do not say that different instances have
different types, but that the class is associated with an instance. That
is a runtime phenomenon, "associated with", it looks like. So in the above
snippet, b has the class Bar that is associated with x. But unlike what I
first said, the type does not change. The association with a particular
object changes.

Are you saying now that there are many classes Foo.Bar, but all are the same
type? In Java (pre-generics, anyway), "class" and "type" are the same
thing.

Anyway, my question wasn't "What type is the object pointed to by 'b'?",
it's "What type is the reference 'b'?" I think we agree that it's Foo.Bar.
 
S

Stefan Ram

Mike Schilling said:
In Java (pre-generics, anyway), "class" and "type" are the same thing.

There are references types and primitive types.
Reference types are classes, interfaces and the null type,
primitive types are »boolean« and numeric types.

types
|
.-----------------'-------------------.
| |
reference types primitive types
| |
.----------'----------. .-------'--------.
| | | | |
classes null type interfaces boolean numeric types
 
M

Mike Schilling

Stefan Ram said:
There are references types and primitive types.
Reference types are classes, interfaces and the null type,
primitive types are »boolean« and numeric types.

types
|
.-----------------'-------------------.
| |
reference types primitive types
| |
.----------'----------. .-------'--------.
| | | | |
classes null type interfaces boolean numeric types

All of which (with the possible exception of the null type) are represented
by classes, e.g. Boolean.TYPE. And the following two sentences are
synonymous:

1. a and b are of the same class.
2. a and b are of the same type.
 
L

Lew

Mike said:
Are you saying now that there are many classes Foo.Bar, but all are the same
type? In Java (pre-generics, anyway), "class" and "type" are the same
thing.

No, I was not saying that. I was agreeing with you that Sun's wording is
sloppy, and trying to make sense of what they really meant. I am now with you
in attempting to "rewrite" the JLS to make sense of what Java actually does

I was also trying to guess at the mindset that forbade
non-compile-time-constant statics in inner classes, and that led me into a
fuzzy world of memes and conceptual structures.

My initial confusion was caused by trustingtoo literally the verbiage Sun and
others provide . I understand now what you were saying and why I was wrong.

- Lew
 
C

Chris Uppal

Lew said:
I really, really want to recommend that you not consider parts of the JLS
as wrong that way. It was very carefully written by a lot of people, and
likely says exactly what it intends to. Besides, by definition Java is
what the JLS says it is, so you fall into a weird solipsistic trap trying
to second guess the very defintion of the language, especially in this
case where there is so much supporting ancillary documentation.

The JLS is a complicated document, which has been carefully written, and
re-written, by some very precise and intelligent people. As such it is like a
large computer program -- it contains bugs. One of the perennial topics here
on C.L.J.P is discussion of whether some passage should be taken exactly as
written, needs to be "interpreted" a little, or is just plain wrong.

The JLS is an authority, true. It is /the/ authority. But, like anything of
human creation, it is not perfect.

Most typically, if the compiler seems to be doing something daft, it will turn
out that it is just following the rules laid down in the JLS, and that those
rules make perfect sense (even if they give rise to counter-intuitive
consequences sometime). Rather rarely (at least until recently) it will turn
out that the compiler is /not/ following the rules of the JLS, and is therefore
buggy. But there is an unknown, and unknowable, number of cases where the
compiler is getting it right, but if anyone traced the details down then they'd
find that JLS required different behaviour -- i.e. that the JLS was buggy.

Put your faith in it by all means, but keep your wits about you when you do.

-- chris
 
M

Mike Schilling

Lew said:
No, I was not saying that. I was agreeing with you that Sun's wording
is sloppy, and trying to make sense of what they really meant. I am
now with you in attempting to "rewrite" the JLS to make sense of what
Java actually does

OK. I'm clearly not understanding what you are saying, though.

By the way, I think the length and complexity of the conversation we've had
so far is evidence that inner class are pretty complicated :)
 
C

Chris Uppal

Lew said:
It occurs to me that many things left out of Java might seem very useful
to highly skilled programmers for certain corner applications, but that
the compromises may make life simpler for the gazillions of journeyman
programmers who do not have quite that deep a grasp on computer science.

But introducing incomplete, and therefore inconsistent, hacks into the language
doesn't make things easier for /anybody/ -- working programmer or theorist.
Simplicity and generality are the things to aim for. Special cases, things
that should work but don't, things that require a theorists' understanding to
use, these are all things to avoid.

Leaving stuff out of the language is fine (albeit frustrating for those who
know how /much/ easier they make programming), since everyone knows where they
are, and simplicity (even the simplicity of emasculation) is a virtue in
itself. What I object to is introducing half-baked approximations to powerful
ideas into the language.

What Java is working towards is a list of more-or-less arbitrary special cases,
complicated by other stuff which (while also ridden with special-case
exceptions) is only comprehensible by theorists.

If a programmer doesn't even try to understand what s/he is doing, and only
programs by rote and by copying other examples, then the maze of exceptions
won't bother them. But I wouldn't want to hire or to work with, and absolutely
/never/ use software created by, any such "programmer".

-- chris
 

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,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top