Why do static and non-static method names collide?

Discussion in 'Java' started by =?ISO-8859-1?Q?Thomas_Gagn=E9?=, Jul 2, 2003.

  1. If a "static" method is like a class method, doesn't it have a different scope
    than an instance method by the same name? For a class TestClass, shouldn't:

    TestClass.main(...);
    and
    TestClass tc = new TestClass();
    tc.main(...);

    be two different methods?

    tgagne:/home/tgagne/work/java cat test.java
    import java.util.*;

    public class test {
    public static void main(String argv[]) {
    (new test()).main(argv);
    }

    public void main(String argv[]) {
    int i;

    for (i = 0; i < argv.length; i++)
    System.out.println(argv);
    }
    }
    tgagne:/home/tgagne/work/java javac test.java
    test.java:8: main(java.lang.String[]) is already defined in test
    public void main(String argv[]) {
    ^
    1 error

    --
    ..tom
    remove dashes in email for replies
    http://isectd.sourceforge.net
     
    =?ISO-8859-1?Q?Thomas_Gagn=E9?=, Jul 2, 2003
    #1
    1. Advertising

  2. "Thomas Gagné" <> wrote in message
    news:...
    > If a "static" method is like a class method, doesn't it have a different

    scope
    > than an instance method by the same name? For a class TestClass,

    shouldn't:
    >
    > TestClass.main(...);
    > and
    > TestClass tc = new TestClass();
    > tc.main(...);
    >
    > be two different methods?
    >
    > tgagne:/home/tgagne/work/java cat test.java
    > import java.util.*;
    >
    > public class test {
    > public static void main(String argv[]) {
    > (new test()).main(argv);
    > }
    >
    > public void main(String argv[]) {
    > int i;
    >
    > for (i = 0; i < argv.length; i++)
    > System.out.println(argv);
    > }
    > }
    > tgagne:/home/tgagne/work/java javac test.java
    > test.java:8: main(java.lang.String[]) is already defined in test
    > public void main(String argv[]) {
    > ^
    > 1 error
    >
    > --
    > .tom
    > remove dashes in email for replies
    > http://isectd.sourceforge.net
    >
    >



    If you have a class:

    public class Test {
    public static void main(String[] args) {
    Test t = new Test();
    t.doFoo();
    }
    public Test() { }
    public static void foo() { System.out.println("foo"); }
    public void doFoo() { this.foo(); }
    }

    The object t is able to access the static method as if were its own (using
    this.foo()). The only thing is that it can't have any references to 'this'
    inside foo. Why would you want to confuse yourself anyways? Its hard enough
    to this mistake...

    public void setText(String text) { text = text; }

    .... in the middle of a bunch of other code.
     
    Miguel De Anda, Jul 2, 2003
    #2
    1. Advertising

  3. =?ISO-8859-1?Q?Thomas_Gagn=E9?=

    pete kirkham Guest

    Thomas Gagné wrote:

    > If a "static" method is like a class method, doesn't it have a different
    > scope than an instance method by the same name? For a class TestClass,
    > shouldn't:
    >
    > TestClass.main(...);
    > and
    > TestClass tc = new TestClass();
    > tc.main(...);
    >
    > be two different methods?


    There's no reason they /should/ be in the same namespace, but I guess
    that the language designers happened to prefer being able to call a
    static method like
    this.main() or just main()
    instead of
    TestClass.main()
    from inside a non-static method of TestClass. As to whether
    ((ThisClass)x).main() when x is null throws a NullPointerexception
    depends on the implementation.

    If the only way to call a static method was <classname>.<methodname>
    then there's no ambiguity, and confusing TestClass.main and main isn't
    that likely, but the language makes the convention that there's only one
    namespace for method names in a class, allowing the invocation to be
    abbreviated.

    As it is also makes access modifiers on static methods a little more
    reasonable: if ThisClass.main can only be accessed from object of
    ThisClass, then it's kinda tied to the instance even if it can't modifiy
    the instance.

    Sometimes it would be nice if (foo.getClass().main()) also worked to
    invoke a static method, ie that the static methods and fields were
    indeed members of the class, but that would require a completely
    different policy on return types and/or dispatch than Java has.


    Pete
     
    pete kirkham, Jul 2, 2003
    #3
  4. Thomas Gagné wrote:
    > If a "static" method is like a class method, doesn't it have a different
    > scope than an instance method by the same name?


    As a matter of fact, no it doesn't.

    > For a class TestClass,
    > shouldn't:
    >
    > TestClass.main(...);
    > and
    > TestClass tc = new TestClass();
    > tc.main(...);
    >
    > be two different methods?


    There are some caveats involving the compile-time type of tc, but in the
    above example the same method is invoked either way, and that method is
    static if the code compiled at all. This exhibits a Java feature (many
    would call it a misfeature) that static members of a class can be
    accessed "through" class instances. Such access does not actually use
    the instance, however -- it is (partially) bound at compile time based
    on the compile-time type of the reference, then resolved to a specific
    static member of the appropriate class at run time. It has high
    confusion potential to access a static member through a reference,
    actually, and most people who express an opinion about it around here
    say "don't do it."


    John Bollinger
     
    John C. Bollinger, Jul 2, 2003
    #4
  5. John C. Bollinger <> scribbled the following:
    > Thomas Gagné wrote:
    >> If a "static" method is like a class method, doesn't it have a different
    >> scope than an instance method by the same name?


    > As a matter of fact, no it doesn't.


    >> For a class TestClass,
    >> shouldn't:
    >>
    >> TestClass.main(...);
    >> and
    >> TestClass tc = new TestClass();
    >> tc.main(...);
    >>
    >> be two different methods?


    > There are some caveats involving the compile-time type of tc, but in the
    > above example the same method is invoked either way, and that method is
    > static if the code compiled at all. This exhibits a Java feature (many
    > would call it a misfeature) that static members of a class can be
    > accessed "through" class instances. Such access does not actually use
    > the instance, however -- it is (partially) bound at compile time based
    > on the compile-time type of the reference, then resolved to a specific
    > static member of the appropriate class at run time. It has high
    > confusion potential to access a static member through a reference,
    > actually, and most people who express an opinion about it around here
    > say "don't do it."


    In fact, in Java, even this works:

    public class Test
    {
    private static void test()
    {
    System.out.println("Hello world!");
    }

    public static void main(String[] args)
    {
    ((Test)null).test();
    }
    }

    and produces the output "Hello world!". If you didn't know test() was
    static, you would probably be scratching your head wondering how it
    could ever work.

    --
    /-- Joona Palaste () ---------------------------\
    | Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
    | http://www.helsinki.fi/~palaste W++ B OP+ |
    \----------------------------------------- Finland rules! ------------/
    "The large yellow ships hung in the sky in exactly the same way that bricks
    don't."
    - Douglas Adams
     
    Joona I Palaste, Jul 3, 2003
    #5
  6. Thomas Gagné <> writes:

    > If a "static" method is like a class method, doesn't it have a
    > different scope than an instance method by the same name?


    No. ALL methods are in a (very loose!) way "class methods", but
    instance methods get an auto-generated parameter for "this".

    For static methods to be separate from instance methods, the keyword
    "static" would need to be encoded into the method signature, and it
    isn't.
     
    Tor Iver Wilhelmsen, Jul 4, 2003
    #6
  7. =?ISO-8859-1?Q?Thomas_Gagn=E9?=

    pete kirkham Guest

    Tor Iver Wilhelmsen wrote:

    > Thomas Gagné <> writes:
    >
    >
    >>If a "static" method is like a class method, doesn't it have a
    >>different scope than an instance method by the same name?

    >
    >
    > No. ALL methods are in a (very loose!) way "class methods", but
    > instance methods get an auto-generated parameter for "this".
    >
    > For static methods to be separate from instance methods, the keyword
    > "static" would need to be encoded into the method signature, and it
    > isn't.


    Since the static keyword is there in the source, and the stsaic bit is
    set in the method info of the class file, and since the compiler/JVM
    has to use this information to generate/use a different calling
    mechanism, it is already part of the signature of the method in the
    sense of the dispatch mechanism, and this difference could be used to
    signify a seperate namespace.

    for example

    public class Foo1 {
    public static void main (String args[]) {
    new Foo2().bar();
    }
    }

    public class Foo2 {
    public void bar () {
    System.out.println("bar");
    }
    }

    javac Foo1
    javac Foo2
    java Foo1
    -->
    bar

    public class Foo2 {
    public static void bar () {
    System.out.println("bar");
    }
    }

    javac Foo2
    java Foo1
    -->
    Exception in thread "main" java.lang.IncompatibleClassChangeError

    ie the signature has been changed sufficently that the dispatch
    mechanism can't call it.


    Pete
     
    pete kirkham, Jul 4, 2003
    #7
  8. pete kirkham <> writes:

    > Since the static keyword is there in the source,


    Source is not checked at runtime

    > and the stsaic bit is set in the method info of the class file,


    Correct

    > and since the compiler/JVM has to use this information to
    > generate/use a different calling mechanism,


    That's compiler, yes. JVM uses a direct index.

    > it is already part of the signature of the method in the sense of
    > the dispatch mechanism,


    But not in the sense of the method table or name relevant for
    reflection, unless you want to change how those work.
     
    Tor Iver Wilhelmsen, Jul 4, 2003
    #8
  9. =?ISO-8859-1?Q?Thomas_Gagn=E9?=

    pete kirkham Guest

    Tor Iver Wilhelmsen wrote:
    > pete kirkham <> writes:


    >>it is already part of the signature of the method in the sense of
    >>the dispatch mechanism,

    >
    >
    > But not in the sense of the method table or name relevant for
    > reflection, unless you want to change how those work.


    I'm not trying to change how it works, as the way it works saves
    confusion between methods in the same class at the expense of confusion
    as to what namespace the method new Foo().bar() is drawn from and the
    occasional need to recompile despite the lack of source code changes in
    a client; there are in effect two namespaces for methods in the JVM, and
    there is a constraint that names in these spaces must not collide.

    In addition to this constraint, there is a constraint that two methods
    cannot have both identical argument types and identical names; strictly
    the signature (as expressed in the name and type info constant
    referenced by the method table) encodes the return type as well as the
    argument types, so the dispatch mechanism could differentiate on this as
    well, but it doesn't, and returns an error if there is a collision.

    In Java there is no method table in the C++ sense; there is only a class
    file format and a specification of the behaviour of the JVM.

    One part of the description of a method in the class file and JVM spec
    is its name, another its argument types and return type, another is a
    bit flag for public/private/protected/package access and for
    static/instance scope. Of these the argument types, the return type, and
    the name and the static/instance bit must agree with the invoked method,
    and the access flags must allow suitable access rights, for the runtime
    to dispatch the method invocation.

    There is no constraint that a JVM finds a method with the same name then
    reports and error if the method differs in the status/instance regard,
    or searches for all methods with the same static/instance bit and
    returns an error than none can be found. In fact, the JVM spec (5.4.3.4)
    says that "If C declares a method with the name and descriptor specified
    by the method reference, method lookup succeeds" for _both_ static and
    virtual methods; so strictly the example I posted _should_ work as the
    spec does not differentiate between lookup from virtual and static
    methods (despite having different instructions for them, and obviously
    different stack states), but only differentiates between interface and
    non-interface method invocations (which are completely the same as far
    as the Java language is concerned). But the example I gave doesn't work
    on any JVM or compiler I've used, and I wouldn't expect it to etiher.

    All compilers/JVMs use the static keyword/bit to differentiate between
    static and virtual methods. This is an inherent part of
    that-which-is-used-to-identify-the-method. Normally,
    that-which-is-used-to-identify-the-method is called its signature.

    Because of the constraints on collisions within the static and instance
    method namespaces, the parameters used to identify a method to the
    reflection API (name + arguments type) suffice. They do not suffice for
    non-reflective method invocation; this requires the static bit agrees
    and the return type agrees; therefore the name given to the reflection
    API is obviously a weaker specifier than that required by the rest of
    the language's dispatch mechanism. The reflection API is a tool whose
    form is defined by additional constraints placed on the language's
    dispatch mechanism; if this mechanism was different, and had fewer
    collision constraints, the inputs to the reflection API would have to
    reflect this.

    These were design decisions, and it is perfectly possible to devise
    dispatch mechanisms where these constraints do not apply: for example
    C++ loosens the return type constraint slightly in that you may return a
    more specific type (though this difference is enough to cause linking
    errors in Java, it wouldn't be enough to effect the reflection API
    lookup arguments, again showing that the reflection API uses a weaker
    specifier).

    So apart from the reflection API, which was designed after the decision
    to dispatch on name+argment types only was made, everywhere Java has to
    identify a method it uses a richer encoding which includes whether the
    method is static or instance, either by keyword in source code for the
    compiler or a bit flag in compiled classes, along with the return type
    as part of its signature.


    Pete
     
    pete kirkham, Jul 5, 2003
    #9
  10. pete kirkham <> writes:

    > All compilers/JVMs use the static keyword/bit to differentiate between
    > static and virtual methods. This is an inherent part of
    > that-which-is-used-to-identify-the-method. Normally,
    > that-which-is-used-to-identify-the-method is called its signature.


    But not in Java, cf. the JVM spec:

    2.10.2 Method Signature

    The signature of a method consists of the name of the method and the
    number and type of formal parameters (§2.10.1) of the method. A
    class may not declare two methods with the same signature.

    That's the part you want to change to be able to confuse the
    programmer by allowing both a static and a non-static method with the
    same name and parameters.

    You may also want to change the JLS which allows a static member to be
    accessed via an instance reference.

    I cannot see you have shown any *benefits* from allowing same-named
    static and non-static metods.
     
    Tor Iver Wilhelmsen, Jul 5, 2003
    #10
  11. =?ISO-8859-1?Q?Thomas_Gagn=E9?=

    pete kirkham Guest

    Tor Iver Wilhelmsen wrote:
    > pete kirkham <> writes:
    >
    >
    >>All compilers/JVMs use the static keyword/bit to differentiate between
    >>static and virtual methods. This is an inherent part of
    >>that-which-is-used-to-identify-the-method. Normally,
    >>that-which-is-used-to-identify-the-method is called its signature.

    >
    >
    > But not in Java, cf. the JVM spec:
    >
    > 2.10.2 Method Signature
    >
    > The signature of a method consists of the name of the method and the
    > number and type of formal parameters (§2.10.1) of the method. A
    > class may not declare two methods with the same signature.
    >
    > That's the part you want to change to be able to confuse the
    > programmer by allowing both a static and a non-static method with the
    > same name and parameters.


    Yes, I'd want to change the spec so that it talks about signature as
    that used for dispatch, like most other dynamically linked systems do,
    and so eliminate the inconsistancy:

    The signature of a method consists of the name of the method, the
    number and type of formal parameters (§2.10.1) of the method, the
    return type and whether it is static or instance method. A change
    to any part of the signature will cause the method not to be located
    at link time.

    As an aid to program clarity, classes may not declare two methods
    whose signatures differ only in return type or instance/static
    scope.

    If I wanted to change the way the JVM operates, I would also add that a
    virtual or interface method may be overridden by one which returns a
    more specific type, eg
    class Foo implements clonable {
    public Foo clone () {...

    which can be useful.

    > You may also want to change the JLS which allows a static member to be
    > accessed via an instance reference.


    Yes. Static methods are never accessed by an instance reference, but by
    the declared compile time type of an expression:

    class A {
    public static foo () {...

    class B extends A {
    public static foo () {...

    A x = new B();
    x.foo();

    calls A.foo() as the type of the variable x is A, even though the type
    of the value of x is B.

    new B().foo()

    calls B.foo() as the type of the stack slot (new B()) is pushed into is B.

    It should not be inconsistant as to whether an overloaded method is
    envoked by the type of the container of the expression or the type of
    the value of the expression.

    In a dynamically linked language it absolutely should not be necessary
    to recompile a class from a source file which has not been changed in
    order for it to link correctly.

    > I cannot see you have shown any *benefits* from allowing same-named
    > static and non-static metods.


    No, but then I've been arguing that the language should match what the
    machine does, and I haven't been arguing for allowing collision between
    static and instance method names.


    Pete
     
    pete kirkham, Jul 5, 2003
    #11
  12. Tor Iver Wilhelmsen wrote:
    > I cannot see you have shown any *benefits* from allowing same-named
    > static and non-static metods.


    It's not unusual in other OO languages to have class-side instance-creation
    methods named identically to instance-side initialization methods--leaving it
    to the programmer which they prefer to call. In most cases, the class-side
    method calls the instance-side method after creating it.

    --
    ..tom
    remove dashes in email for replies
    http://isectd.sourceforge.net
     
    =?ISO-8859-1?Q?Thomas_Gagn=E9?=, Jul 5, 2003
    #12
  13. =?ISO-8859-1?Q?Thomas_Gagn=E9?=

    cgbusch Guest

    > There are some caveats involving the compile-time type of tc, but in the
    > above example the same method is invoked either way, and that method is
    > static if the code compiled at all. This exhibits a Java feature (many
    > would call it a misfeature) that static members of a class can be
    > accessed "through" class instances. Such access does not actually use
    > the instance, however -- it is (partially) bound at compile time based
    > on the compile-time type of the reference, then resolved to a specific
    > static member of the appropriate class at run time. It has high
    > confusion potential to access a static member through a reference,
    > actually, and most people who express an opinion about it around here
    > say "don't do it."


    The trouble I have with accessing static methods through the class
    name is it requires more code to be changed when refactoring occurs.
    For example:
    class X { static void foo(); }
    class Y { static void foo(); }
    ....
    X instance=new X();
    X.foo(); //sprinkle in code 1 million times.

    You now refactor your code to use Y. 1 million + 1 lines to change.
    But if you used the instance to reference foo():
    X instance=new X();
    instance.foo(); //sprinkle in code 1 million times.
    You only need to change 1 line:
    Y instance=new Y();

    This is why I hate casts. It sprinkles annoying non-refactorable
    code, when the compiler could easily figure it out.
    x=(StupidCast)object;
    The compiler knows what type of object x is! It could put the cast in.
    I would argue that the compiler should implicitly cast any object to
    the left operand's type in an assignment. Imagine how much cleaner
    Collections code would be.
    (I argue that casts in an assignment does not produce less buggy code,
    but rather increases it, since people are less willing to refactor.)

    --
    CB
     
    cgbusch, Jul 5, 2003
    #13
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Gary
    Replies:
    1
    Views:
    3,994
    Ryan Stewart
    Jan 16, 2004
  2. Michael
    Replies:
    3
    Views:
    4,945
    Adam Jenkins
    Jan 27, 2004
  3. Mr. SweatyFinger

    why why why why why

    Mr. SweatyFinger, Nov 28, 2006, in forum: ASP .Net
    Replies:
    4
    Views:
    912
    Mark Rae
    Dec 21, 2006
  4. Mr. SweatyFinger
    Replies:
    2
    Views:
    2,004
    Smokey Grindel
    Dec 2, 2006
  5. rickman
    Replies:
    5
    Views:
    428
    rickman
    Mar 30, 2013
Loading...

Share This Page