Skip to main content

Make 'class' keyword work the same (similar) way as 'this'

34 replies [Last post]
patrikbeno
Offline
Joined: 2004-10-11

'this' is always available in instance scope and you can use it to access all members of 'this' instance

Likewise, 'class' should always be available for accessing static context (without the need for explicit class specification)

<br />
class MyClass {<br />
   static {<br />
      /* no need for explicit Myclass.class.getName() reference */<br />
      System.out.println("Initializing class "+class.getName());<br />
   }<br />
}<br />

Old way remains in effect, new way does not breaks anything.
Possible conflicts should be solved the same way as 'this' conflicts in inner classes - explicit reference

Easy to do, and clears language a little bit. Both 'class' and 'this' will have the same style of usage (just different contexts)

added 20041025
Discussion shows that I need to clarify what I suggest: It's only syntactic sugar, no changes to bytecode or JVM.

Message was edited by: patrikbeno

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
keithkml
Offline
Joined: 2003-06-10

IntelliJ IDEA has a "Copy Class" refactoring that solves this problem by changing all references to the original class, in the copied class.

forax
Offline
Joined: 2004-10-07

1) yes, you're right

2a) yes, it's an hack.

2b) yes but i'm not agree with the classpath search
because the class is in the stacktrace,
you can suppose that it is loaded
in the classloader cache.

Another idea related to class keyword :

The jdk1.5 introduces covariance on return type
but all pre-Tiger classes couldn't change the
signature of theirs methods like clone() or initCause()
without disturbs inherited class compilation.

I propose a new keyword (oups) Self that reference
the Type the current class.

with this, signatures of clone/initCause could be
Self clone()
Self initCause(Throwable t)

To be backward compatible, it's possible
to override a method this Self by a method
with Object. But the compiler generate a warning.

class Object {
Self clone() {...}
}

class MyClassBeforeTiger {
Object clone() {...} // warning, must be Self
// but compile
}

the current class could be represented by
Self.class that not change the java grammar

Rémi Forax

monika_krug
Offline
Joined: 2004-10-14

> 1) Using IDEs to do these kind of things is a
> woraround not solution. And we know what the solution
> is so why should we use workarounds?

If a solution for a problem brings about new problems, it may be better to let the IDE do the work for you instead of let the compiler do it.

When you rename the class, there are plenty of places elsewhere in your code that you have to modify. You would let your IDE do that, because obviously the compiler can't (wait, maybe I should suggest a @renamed tag ;-) ), so why not let it do the renaming of that one, too?

Also, there are several of other things IDEs do that the compiler could do, but does not do for a good reason, one example is "inherit constructors from super class". Often one wants all the constructors from the super class in the subclass, but one has to copy them manually when one is not using an IDE. The language could have been defined to inherit the constructors. But it wasn't, because that way one could not get rid of constructors.

So a solution with an IDE is not necessarily a workaround.

> 2) Using keyword 'class' for class declaration is
> allowed only outside the code block. There is no
> conflict. See:
>
> [code]
> class MyClass {
> class Inner {} -- legal
>
> Class me = class; -- can be legal
>
> Class other = class Other {} -- illegal
>
> static {
> class Another {} -- illegal
> Class me = class; -- can be legal
> }
>
> static void go() {
> class MyClass {} -- illegal
> print(class+" going()"); -- can be legal
> }
> }
> [/code]

It is legal to define a class inside a method or initializer.

> I still don't see any problem with this simple but
> useful syntactic sugar.

I guess there would probably be not too much trouble with the parsers, even though "class" is permitted in code blocks. "class Name {" for defining a class can probably be distinguished from "class.someThing()" or "... = class;" just like from "Literal.class".

So, +1, if it makes no serious problems for the compiler, as it seems to be very helpful for some fellow developers :-) .

Monika.

patrikbeno
Offline
Joined: 2004-10-11

[i]> When you rename the class, there are plenty of places elsewhere in your code that you have to modify. You would let your IDE do...[/i]

This is called refactoring and IDE that parses and validates source can reliably do the change. In case of literals no IDE can reliably do that change so they usually ASK user for permission.

So in case of reliable refactoring you just let IDE do the job, while with literals you have to go carefully through all literal occurences and validate the proposed change.

Ad. inheriting constructors - this is language feature and it's related to security. And although this sometimes really sucks (consider exceptions), I would not want to change this because I understand and agree with the reason (security). Conslusion is: this is the right job for IDEs, I agree.

However, in our case (renaming hardcoded class names literals) using IDEs for this task is a workaround.

[i]> It is legal to define a class inside a method or initializer.[/i]

Well, you caught me on this one :-) I never used it (anonnymous classes were just enough for me) so I forgot about this possibility. One can always learn something new or recall forgotten, even in this funny 'class' discussion. That makes me humble and grateful :-)
And I think we're square now, I caught you with that 'instanceof' operator, do you remember? ;-)

Anyway, this means that there will more trouble that I thought. Still feasible but what is the real cost? We don't know so we will have to leave this up to javac guys.

forax
Offline
Joined: 2004-10-07

why do you need a new keyword if a simple method
do what you want ?

public static Class getCurrentClass() {
try {
return Class.forName(
new Throwable().getStackTrace()[1].getClassName());
} catch (ClassNotFoundException e) {
throw new AssertionError(e);
}
}

Rémi Forax

patrikbeno
Offline
Joined: 2004-10-11

1) I am not inventing new keyword. If you haven't noticed, 'class' already IS a keyword. I only want to make a better use of it.

2a) Your magic method will not always work in architecture with multiple classloaders (unless you put that method into every class which does not make sense).

2b) It is just ugly. Fine hack but still ugly. In static context, it creates new Throwable with possibly huge array of StackTraceElement instances, followed with a hashtable or even worse system classpath search (Class.forName) just to find out something that was already known at compile time...

Message was edited by: patrikbeno

monika_krug
Offline
Joined: 2004-10-14

That's really ugly and uses lots of ressources. And not all VM implementations support stack trace, I believe, e.g. J2ME CLDC does not.

Monika.

patrikbeno
Offline
Joined: 2004-10-11

1) Using IDEs to do these kind of things is a woraround not solution. And we know what the solution is so why should we use workarounds?

2) Using keyword 'class' for class declaration is allowed only outside the code block. There is no conflict. See:

[code]
class MyClass {
class Inner {} -- legal

Class me = class; -- can be legal

Class other = class Other {} -- illegal

static {
class Another {} -- illegal
Class me = class; -- can be legal
}

static void go() {
class MyClass {} -- illegal
print(class+" going()"); -- can be legal
}
}
[/code]

I still don't see any problem with this simple but useful syntactic sugar.

dgriffit
Offline
Joined: 2004-10-13

Actually, classes can be defined inside code blocks, it's just that nobody does so. It's a valid part of the inner class specification. Google for "limited-scope inner class". I've never seen one outside of some very complete tutorials, though.

monika_krug
Offline
Joined: 2004-10-14

I have used them for listeners. I don't like anonymous classes.

Monika.

patrikbeno
Offline
Joined: 2004-10-11

So it's you who misses the point, not me.
My proposal is not about runtime or VM, it's about compiler.

if compiler sees 'class' reference (like 'class.getName()'), it will expand this reference with regard to the static context known at compile time. And it is known. If mentioned reference occurs in class MyClass, the 'class.getName()' expands to 'MyClass.class.getName()'.

No changes to the bytecode or JVM, it's a syntactic sugar.

Message was edited by: patrikbeno

kcpeppe
Offline
Joined: 2003-06-15

> So it's you who misses the point, not me.
> My proposal is not about runtime or VM, it's about
> compiler.
>
> if compiler sees 'class' reference (like
> 'class.getName()'), it will expand this reference
> with regard to the static context known at compile
> time. And it is known. If mentioned reference occurs
> in class MyClass, the 'class.getName()' expands to
> 'MyClass.class.getName()'.
>
> No changes to the bytecode or JVM, it's a syntactic
> sugar.
>
>
> Message was edited by: patrikbeno

*blinks*... I think that I wished that Java did have a this keyword that worked in a static context. What I was pointing out were the reasons that it did not.

kobit
Offline
Joined: 2003-06-13

Are you talking about 'getClass()' method replacement?

Artur

patrikbeno
Offline
Joined: 2004-10-11

No. I mean

'class' should be equivalent to 'ThisClassWhereTheCursorIs.class'

getClass() is instance's method, something completely different. 'class' keyword has static compile-time meaning.

johnweidner
Offline
Joined: 2006-02-07

Although, not the language feature you are looking for, you could add the class below, and then every classes logging initialization could look exactly the same. So you wouldn't have the refactoring issue you discussed.

Each classes logging initialization would look similar to:

private static final LogProvider log = Logging.getLog( ClassName.getQualifiedClassName() );

here's the ClassName source
------------------------------------
/**
* Utilities for getting the calling class's name and package name.
*
* @author SBrunning
*
*/
public class ClassName {

/**
* Get the calling class's fully qualified class name.
*
* @return The calling class's fully qualified class name.
*/
public static String getQualifiedClassName() {
return new Exception().getStackTrace()[1].getClassName();
}

/**
* Get the calling class's class name.
*
* @return The calling class's class name.
*/
public static Object getClassName() {
String qualifiedClassName = new Exception().getStackTrace()[1].getClassName();
return qualifiedClassName.substring(qualifiedClassName.lastIndexOf('.') + 1, qualifiedClassName.length());
}

/**
* Get the calling class's package name.
*
* @return The calling class's package name.
*/
public static Object getPackageName() {
String qualifiedClassName = new Exception().getStackTrace()[1].getClassName();
return qualifiedClassName.substring(0, qualifiedClassName.lastIndexOf('.'));
}
}

dog
Offline
Joined: 2003-08-22

the 'class' keyword would be very useful. It is a common pattern to say something like:

private final static Logger = new Logger(MyClass.class.getName());

when copying around code it is often easy to miss the reference to the MyClass class and end up logging in the wrong place. The 'class' keyword would solve this.

I really missed this when I moved from Smalltalk to C++, and I really miss this in Java too. It just makes code cleaner.

_forest_
Offline
Joined: 2003-07-19

Java architechture does not suppose that you are copying your code all over application, Ctrl+C & Ctrl+V programming is not a good practice.
Why does it make code cleaner ? May be only your Copy/Paste programs...

patrikbeno
Offline
Joined: 2004-10-11

You just don't get it, do you?
It makes my code cleaner because I don't have redundant class name references where 'class' keyword does it all.
Imagine you would be forced to pass explicit 'this' when calling all methods.
And finally, if Logger stuff is needed in all your classes, what architecture would you suggest to solve this? Speaking about architecture not tools

monika_krug
Offline
Joined: 2004-10-14

> 'this' is always available in instance scope and you
> can use it to access all members of 'this' instance
>
> Likewise, 'class' should always be available for
> accessing static context (without the need for
> explicit class specification)[code]
> class MyClass {
> static {
> /* no need for explicit
> plicit [u]Myclass.class.getName()[/u] reference */
> System.out.println("Initializing class
> class "+[u]class.getName()[/u]);
> }
> }[/code] > Old way remains in effect, new way does not breaks
> anything.
>
> Easy to do, and clears language a little bit. Both
> 'class' and 'this' will have the same style of usage
> (just different contexts)

Can you give an example when this would be useful?

> Possible conflicts should be solved the same way as
> 'this' conflicts in inner classes - explicit
> reference

There are no possible conflicts as inner classes cannot have static methods.

Monika.

patrikbeno
Offline
Joined: 2004-10-11

1) i gave you an example, in the very first post. it is useful everywhere where you today use explicit reference (MyClass.class). I mean if MyClass.class means ThisClass.class then explicit reference is redundant. Keyword 'class', when stading alone, points always to this class (class where it is used).

2a) because inner classes do not have their own static context, expression 'class' would point to the enclosing class. in fact, inner classes inherit static context of the enclosing class so this is logical
2b) conflicts, if any, would be solved like 'this' conflicts: e.g. inner classes have two 'this' references (their own and 'this' of the enclosing class. If you want to access 'this' of the enclosing class, you use explicit reference: 'Outer.this'. This already works and 'class' keyword should behave the same way

Message was edited by: patrikbeno

monika_krug
Offline
Joined: 2004-10-14

No, a real example. You don't really want to print out "initializing class ...", do you?

Why don't you use
System.out.println("Initializing class MyClass");
instead of
System.out.println("Initializing class "+class.getName());
?
What is the benefit?

Monika.

patrikbeno
Offline
Joined: 2004-10-11

Benefit is that you can refactor your code safely and you will not end up with class RenamedClass printing out 'Initializing MyClass'

Real example is that [b]every time[/b] you need to access your class instance in a static context, you have to explicitly specify is name which is just needlessly verbose.

[code]
class MyClassWithVeryLongSelfExplanatoryName {
static {
SomeManager.registerClass( MyClassWithVeryLongSelfExplanatoryName.class );
}
}
[/code]

Further, if you decide to copy&paste this small fragment of code to every new class that needs the same call, you have to fix class reference manually which would be otherwise not neccessary.
[code]
class Another {
static {
SomeManager.registerClass( class );
}
}
[/code]

monika_krug
Offline
Joined: 2004-10-14

> Benefit is that you can refactor your code safely and
> you will not end up with class RenamedClass printing
> out 'Initializing MyClass'

Let your IDE do this for you :-) . E.g. Eclipse would also update it in string literals.

> Further, if you decide to copy&paste this small
> fragment of code to every new class that needs the
> same call, you have to fix class reference manually
> which would be otherwise not neccessary.
> [code]class Another {
> static {
> SomeManager.registerClass( class );
> }
> }[/code]

Okay, you have a point there.

However, the keyword class is already reserved for defining a class. Wouldn't your suggested change result in compiler and parser problems?

Monika.

dgriffit
Offline
Joined: 2004-10-13

Parser issues are what I thought of first, as well, but I played around with the grammar a bit, and it looks fine. If this suggestion were accepted (which I strongly hope), it would represent the only way an expression could begin with the "class" keyword token. I'm pretty sure that this would introduce no grammar ambiguities, and not complicate parser development noticably. It would also clean up a lot of moderately ugly code used to initialize classes (particularly initializing logging for classes), and is generally worth doing.

kcpeppe
Offline
Joined: 2003-06-15

> 'this' is always available in instance scope and you
> can use it to access all members of 'this' instance
>
> Likewise, 'class' should always be available for
> accessing static context (without the need for
> explicit class specification)

Now, this is an interesting observation... :)
Again, in a language where all elements are treated as first class objects, the keyword this would have context inside a class method. Unfortunately, changing Java to support such a notion at this late date would require some serious reconstructive surgery. This is because in order to this to have meaning, it has to refer to some context. In Java, static methods have no containing context. In other OO languages such as Smalltalk, a classes are instances of the class Class and as such, "static methods" are actually instance methods of the instance class (and yes, there is a bit of circularity in there ;)).

patrikbeno
Offline
Joined: 2004-10-11

I am not sure about your standpoint. Do you agree with this or not?

Let this be how it is. It's fine.
Just let's make 'class' keyword always point to the actual static context. You always have one.

kcpeppe
Offline
Joined: 2003-06-15

> I am not sure about your standpoint. Do you agree
> with this or not?

I agree that it's an abnormality but unfortunately it's a little late in the game to be making this type of change. This of course comes with my usual disclaimer that these experimential things should not be applied to the production version of Java ;)
>
> Let this be how it is. It's fine.
> Just let's make 'class' keyword always point to the
> actual static context. You always have one.

That is the problem, you really don't have a context while in a static method :|

patrikbeno
Offline
Joined: 2004-10-11

At compile time, you always have static context.
Compiler can always expand 'class.getName()' to 'Actual.class.getName()'. Why should I be bothered to type it?

And that's all I want and it's easy. javac guys would be able to do it in an hour or less

kcpeppe
Offline
Joined: 2003-06-15

You are correct.. you do have a static context.. trouble is, it's the same context for ALL static methods. If this was to refer to that space, then..... you'd be refering to quite a bit...

patrikbeno
Offline
Joined: 2004-10-11

I can't see your point.

in my example right on the top you use 'MyClass.class' to obtain Class instance. I want to remove the need for explicit MyClass reference, there is no reason for it. 'class' just does it. Always. What's wrong with that? Still don't understand.

kcpeppe
Offline
Joined: 2003-06-15

> I can't see your point.
>
> in my example right on the top you use
> 'MyClass.class' to obtain Class instance. I want to
> remove the need for explicit MyClass reference, there
> is no reason for it. 'class' just does it. Always.
> What's wrong with that? Still don't understand.

The thing is, an instance acts as a containing name space or context. Statics all live in the same name space, there is no containment as there is in objects. Now, I've not been involved in VM development for quite some time but I do recall that this lack of containment was a problem for those connecting OODMS to Java.

monika_krug
Offline
Joined: 2004-10-14

> Statics all live in the same name
> space, there is no containment as there is in
> objects.

If this is so, how can two classes have static methods of the same name?

Monika.

kcpeppe
Offline
Joined: 2003-06-15

> > Statics all live in the same name
> > space, there is no containment as there is in
> > objects.
>
> If this is so, how can two classes have static
> methods of the same name?
>
> Monika.

I believe they are qualified by the class name. That said, they still all live in the same static name space which I believe is at the root of the problem.

patrikbeno
Offline
Joined: 2004-10-11

Have you read my post, my friend? it should be right below this one.

Or click here http://forums.java.net/jive/thread.jspa?messageID=4302#4302