Czemu class nie może być static imported?

0

Skoro mogę użyć pola/metody statycznej bez nazwy klasy

class Foo {
    public static void main() {
        bar(); // mogę zawołać bar - czyli Foo.bar()
        class; // nie mogę zawołać class - czyli Foo.class
    }

    static void bar() {}
}

Jest jakiś powód czemu tak się nie da? Oprócz tego że brzydko wygląda?

0

class nie jest polem ani metodą, które można zaimportować. class to słowo kluczowe i reprezntuje albo start definicji klasy albo literał. Skąd kompilator miałby wiedzieć, czy chcesz utworzyć lokalną klasę i zapomniałeś dopisać jej ciała, czy odwołujesz się do literału?

0
Michał Sikora napisał(a):

class nie jest polem ani metodą, które można zaimportować. class to słowo kluczowe i reprezntuje albo start definicji klasy albo literał. Skąd kompilator miałby wiedzieć, czy chcesz utworzyć lokalną klasę i zapomniałeś dopisać jej ciała, czy odwołujesz się do literału?

Czyli mówisz że nie da się odnieść do class bez nazwy klasy wcześniej, żeby nie tworzyć niejednoznaczności dla parsera?

0

To jeden aspekt. Ale głównym powodem dlaczego nie można importować jest to, że class nie jest ani polem ani metodą, więc nie może być statycznie importowane i nie da się do niego ot tak odwołać. To po prostu konstrukcja w języku pozwolająca pobrać java.lang.Class.

0
Michał Sikora napisał(a):

To jeden aspekt. Ale głównym powodem dlaczego nie można importować jest to, że class nie jest ani polem ani metodą, więc nie może być statycznie importowane i nie da się do niego ot tak odwołać. To po prostu konstrukcja w języku pozwolająca pobrać java.lang.Class.

Twój argument brzmi trochę jak "nie bo nie".

Michał Sikora napisał(a):

class nie jest ani polem ani metodą, więc nie może być statycznie importowane.

Dlaczego nie? (tylko nie mów "dlatego że nie jest polem" - to nie jest powód).

0

Ale to jest dokładnie ten powód. Pojedyczne statyczne importowanie pozwala na deklarowanie tylko i wyłącznie elementów, które są częścią nazwanego typu. class nie jest częścią nazwanego typu tylko literałem klasowym.

https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.8.2
https://docs.oracle.com/javase/specs/jls/se11/html/jls-7.html#jls-SingleStaticImportDeclaration

0
Michał Sikora napisał(a):

Pojedyczne statyczne importowanie pozwala na deklarowanie tylko i wyłącznie elementów, które są częścią nazwanego typu.

No ale czemu pozwala tylko na takie?

0
TomRiddle napisał(a):

Twój argument brzmi trochę jak "nie bo nie".

I prawdopodobnie jest to właściwy argument. .class jest traktowane w uproszczony sposób i dlatego gramatyka języka jest prostsza. Zauważ też, że nie da się zrobić int[][].class.class.class, ale da się zrobić int[][].class.

this też jest traktowany specjalnie. Nie da się np zrobić obiekt.this, chociaż this z pozoru wygląda jak pole w klasie.

Za to możesz zrobić coś takiego:

class Test {
    void m1() { }
    void m2(Test this) { }
}

https://stackoverflow.com/a/24291558

0

Można też przewrotnie zapytać, jaki był zakres JSRa wprowadzającego statyczne importy? I argumentować: "class nie było w zakresie" ;-)

0
Wibowit napisał(a):
TomRiddle napisał(a):

Twój argument brzmi trochę jak "nie bo nie".

.class jest traktowane w uproszczony sposób i dlatego gramatyka języka jest prostsza. Zauważ też, że nie da się zrobić int[][].class.class.class, ale da się zrobić int[][].class.

Nie do końca uznaję to za odpowiedź. Chodziło mi bardziej o odpowiedź natury:

  • Dlaczego overload'owane metody nie mogą różnić się tylko return type'm?

  • Bo to rodziloby niejednoznaczność wywołania metody w compile-time, np

class T {
  static Integer get() {} 
  static Object get() {} 
}

Object o = T.get();  // którą wywołać?

I to jest prawdziwy powód dla którego takie overload'owanie nie jest uznawane.

Ale odpowiedzi typu: "Nie można tak zrobić, bo gramatyka języka jest prostsza przez to że class jest traktowane inaczej"... no dla mnie jest niezadowalająca.

0

Wydaje mi się, że przykład z przeładowaniem ma inną naturę. Bardziej analogiczne byłoby pytanie "Czemu nie może być dwóch klas publicznych w jednym pliku?". Odpowiedź - "Bo nie.".

Czemu nie można statycznie importować class? Bo nie. Z kolei czemu wewnątrz klasy nie mogę używać po prostu class? Bo rodziłoby to niejednoznaczność dla kompilatora czy to nowa, niedokończona klasa czy chęć pobrania java.lang.Class. Chociaż to jeszcze dałoby się okiełznać.

Może nie da się importować bo i tak musiałbyś dookreślić, o które class Ci chodzi.

import static Bar.class;

public Foo {
  void foo() {
    var x = class; // Czym jest "x"? 
  } 
} 

Możliwe, że to było powodem, dla którego statyczne importowanie nie zostało rozszerzone o możliwość deklarowania class - bo i tak nie mógłbyś się bezpośrednio do tego class jednoznacznie odwołać. Ale mam wrażenie, że powód znają projektanci języka i ludzie siedziący głęboko w temacie.

0
Michał Sikora napisał(a):

Wydaje mi się, że przykład z przeładowaniem ma inną naturę.

Przykład jest nieistotny - chciałem podać o jaką odpowiedź mi chodziło.

Bardziej analogiczne byłoby pytanie "Czemu nie może być dwóch klas publicznych w jednym pliku?". Odpowiedź - "Bo nie.".

Wymuszenie żeby namespace (package) był taki sam jak struktura folderu oraz wymuszenie by plik nazywał się tak jak klasa publiczna miały znacznie poprawiać czytelność kodu - w PHP nie ma takich wymuszeń, i jest c***owo :/ Więc to nie jest przykład "nie, bo nie" tylko jest jakiś powód.

Może nie da się importować bo i tak musiałbyś dookreślić, o które class Ci chodzi.

static import Bar.class;

public Foo {
  void foo() {
    var x = class; // Czym jest "x"? 
  } 
} 

Moim zdaniem to x powinno być Bar.class. A gdyby nie było importa, wtedy class odniosłoby się do pliku w którym jest, czyli Foo.class. Nie widzę tu niejednoznaczności.

bo i tak nie mógłbyś się bezpośrednio do tego class jednoznacznie odwołać.

Gdyby to co mówisz było prawdziwe, to do dwóch klas o takich samych nazwach ale różnych namespace'ach (com.Foo, org.Foo) też nie mógłbyś się odnieść. Ale możesz. Więc do class też byś mógł.

0
TomRiddle napisał(a):

Bardziej analogiczne byłoby pytanie "Czemu nie może być dwóch klas publicznych w jednym pliku?". Odpowiedź - "Bo nie.".

Wymuszenie żeby namespace (package) był taki sam jak struktura folderu oraz wymuszenie by plik nazywał się tak jak klasa publiczna miały znacznie poprawiać czytelność kodu - w PHP nie ma takich wymuszeń, i jest c***owo :/ Więc to nie jest przykład "nie, bo nie" tylko jest jakiś powód.

Nazwa pakietu powiązana ze strukturą folderu faktycznie zwiększa czytelność i ułatwia poruszanie się po kodzie. Kilka publicznych klas w jednym pliku potrafi poprawić czytelność w niektórych przypadkach moim zdaniem. Jest to zbyt subiektywny argument. Może faktycznie autorzy Javy się tym kierowali, ale jest to ich kolektywna opinia a nie jakaś obiektywna przesłanka.

static import Bar.class;

public Foo {
  void foo() {
    var x = class; // Czym jest "x"? 
  } 
} 

Moim zdaniem to x powinno być Bar.class. A gdyby nie było importa, wtedy class odniosłoby się do pliku w którym jest, czyli Foo.class. Nie widzę tu niejednoznaczności.

A czemu nie Foo.class? Czemu import class powinien mieć pierwszeństwo nad samą klasą, w której jest użyty i zachowywać się inaczej niż statyczny import pól i metod?

package bar;

public class Bar {
  public static final String name = Bar.class.getSimpleName();

  public static void printName() {
    System.out.println();
  }
}

-----------------

package baz;

import static bar.Bar.printName;
import static bar.Bar.name;

public class Baz {
  public static final String name = Baz.class.getSimpleName();

  public static void printName() {
    System.out.println(Baz.class.getSimpleName());
  }

  public static void test() {
    printName();
    System.out.println(name);
  }
}

-----------------

import baz.Baz;

public final class App {
  public static void main(String[] args) {
    Baz.test();
  }
}

Wynik:
Baz
Baz

Gdyby to co mówisz było prawdziwe, to do dwóch klas o takich samych nazwach ale różnych namespace'ach (com.Foo, org.Foo) też nie mógłbyś się odnieść. Ale możesz. Więc do class też byś mógł.

A jak wygląda takie odniesienie się w jednym pliku do dwóch klas o tej samej nazwie z różnych przestrzeni nazw?

0
Michał Sikora napisał(a):

A jak wygląda takie odniesienie się w jednym pliku do dwóch klas o tej samej nazwie z różnych przestrzeni nazw?

Jedna z nich musi mieć wyspecyfikowany namespace, druga może być zaimportowana.

0
Michał Sikora napisał(a):

Nazwa pakietu powiązana ze strukturą folderu faktycznie zwiększa czytelność i ułatwia poruszanie się po kodzie. Kilka publicznych klas w jednym pliku potrafi poprawić czytelność w niektórych przypadkach moim zdaniem. Jest to zbyt subiektywny argument. Może faktycznie autorzy Javy się tym kierowali, ale jest to ich kolektywna opinia a nie jakaś obiektywna przesłanka.

Subiektywny, obiektywny czy nie - jest podany powód. Właśnie o taki powód mi chodziło, kiedy zapytałem czemu class nie może być importowane.

0
Michał Sikora napisał(a):

A czemu nie Foo.class? Czemu import class powinien mieć pierwszeństwo nad samą klasą, w której jest użyty i zachowywać się inaczej niż statyczny import pól i metod?

Z polami i metodami statycznymi jakoś jest to rozwiązane i nie ma ambiguity. Czemu miałoby się nie dać z class?

0
TomRiddle napisał(a):

Jedna z nich musi mieć wyspecyfikowany namespace, druga może być zaimportowana.

No dokładnie. W ten sposób pozbywasz się niejednoznaczności. Nie możesz np. zaimportować foo.Foo do bar.Foo, bo nie pozwoli na to kompilator i musisz się do foo.Foo odwoływać po pełnej nazwie. W najlepszym przypadku import foo.Foo mógłby być ignorowany, tak jak ignorowane są statyczne importy w przypadku konfliktów nazw.

TomRiddle napisał(a):

Z polami i metodami statycznymi jakoś jest to rozwiązane i nie ma ambiguity. Czemu miałoby się nie dać z class?

Jest rozwiązane w ten sposób, że import jest ignorowany. Faktycznie, mogliby to dodać również dla class. Tylko bez sensu wydaje mi się dodawanie czegoś tylko po to, żeby móc to ignorować. Można się zastanawiać, czemu nie można wewnątrz klasy użyć po prostu class do pobrania java.lang.Class. Na to żadnego pomysłu nie mam. Podejrzewam, że głównie - bo szkoda zachodu dla takiego przypadku, kiedy alternatywa Foo.class wewnątrz Foo nie jest uciążliwa.

1

A może dlatego, że dla większości "szarych" programistów zapis:

Class c = class;

sugerowałby, że można zrobić też tak:

Double d = double;

lub

Class d = double;

Skoro jedno słowo kluczowe może być zmienną to dlaczego nie pozostałe?

Po drugie zgodnie z Twoją filozofią można by też zapisać tak:

Field f = class.getField("abc");

jeśli dla słowa kluczowego class można wywołać metodę, to dlaczego nie dla pozostałych klas:

Field f = interface.getField("abc");
Field f = enum.getField("abc");

albo odwołać się do pól:

int maxValue = int.MAX_VALUE;

przecież taki zapis bez problemu można by przetłumaczyć w trakcie kompilacji, podstawiając pod int po prawej stronie klasę Integer.
To, że możesz wywnioskować import bez podania nazwy klasy, w tej sytuacji jest chyba mało istotne. Jeśli zasadą jest, że pola i metody mają klasy, a nie słowa kluczowe, to twórcy chyba trzymali się tej zasady.

0
cs napisał(a):

A może dlatego, że dla większości "szarych" programistów zapis:

Class c = class;

sugerowałby, że można zrobić też tak:

Double d = double;

lub

Class d = double;

Skoro jedno słowo kluczowe może być zmienną to dlaczego nie pozostałe?

Po drugie zgodnie z Twoją filozofią można by też zapisać tak:

Field f = class.getField("abc");

jeśli dla słowa kluczowego class można wywołać metodę, to dlaczego nie dla pozostałych klas:

Field f = interface.getField("abc");
Field f = enum.getField("abc");

albo odwołać się do pól:

int maxValue = int.MAX_VALUE;

przecież taki zapis bez problemu można by przetłumaczyć w trakcie kompilacji, podstawiając pod int po prawej stronie klasę Integer.
To, że możesz wywnioskować import bez podania nazwy klasy, w tej sytuacji jest chyba mało istotne. Jeśli zasadą jest, że pola i metody mają klasy, a nie słowa kluczowe, to twórcy chyba trzymali się tej zasady.

Dlatego że istnieje coś takiego jak Obiekt.class, a nie istnieje nic takiego jak Obiekt.interface ani Obiekt.double.

0
Michał Sikora napisał(a):

Można się zastanawiać, czemu nie można wewnątrz klasy użyć po prostu class do pobrania java.lang.Class. Na to żadnego pomysłu nie mam.

No przecież ja właśnie o to pytam od samego początku :|

1
TomRiddle napisał(a):
Michał Sikora napisał(a):

Można się zastanawiać, czemu nie można wewnątrz klasy użyć po prostu class do pobrania java.lang.Class. Na to żadnego pomysłu nie mam.

No przecież ja właśnie o to pytam od samego początku :|

A jaki problem rozwiązałoby to statyczne importowanie class?

0

Tak jak @yarel napisał. Statyczne importowanie nie jest z tym związane.

0
yarel napisał(a):
TomRiddle napisał(a):
Michał Sikora napisał(a):

Można się zastanawiać, czemu nie można wewnątrz klasy użyć po prostu class do pobrania java.lang.Class. Na to żadnego pomysłu nie mam.

No przecież ja właśnie o to pytam od samego początku :|

A jaki problem rozwiązałoby to statyczne importowanie class?

Ten sam który rozwiązuje statyczne importowanie metod.

2

Ale class nie jest metodą, jak chcesz to podciągnąć pod statyczne importowanie metod? Dla przypomnienia wywołanie metody wymaga operatora (), class tego nie ma. To, że działa jak metoda nie znaczy, że jest metodą.

0
cs napisał(a):

Ale class nie jest metodą, jak chcesz to podciągnąć pod statyczne importowanie metod? Dla przypomnienia wywołanie metody wymaga operatora (), class tego nie ma.

Noi co z tego? To nie jest nic z czym parser by sobie nie poradził. Dla pół statycznych jakoś daje rade.

To, że działa jak metoda nie znaczy, że jest metodą.

Odniosłem się do metod statycznych, bo przedmówca zaproponował że class nie mogłoby być importowane/używane bez klasy bo rodziloby to niejednoznaczność. Ja tylko dodałem, że to nie prawda, bo metod statycznych i pół używamy ciągle a niejednoznaczności nie ma. Z punktu widzenia parsera to jedno i to samo.

0

Chodzi mi o to:

class Foo {
  static int field;
  static int method() {} 

  public static void main() {
      // można 
      Foo.field
      Foo.method() 
      Foo.class
      field 
      method() 
      // nie można 
      class
  } 
} 

Czemu ten wyjątek?

0
TomRiddle napisał(a):

Odniosłem się do metod statycznych, bo przedmówca zaproponował że class nie mogłoby być importowane/używane bez klasy bo rodziloby to niejednoznaczność. Ja tylko dodałem, że to nie prawda, bo metod statycznych i pół używamy ciągle a niejednoznaczności nie ma. Z punktu widzenia parsera to jedno i to samo.

Przepraszam, ale czytasz, to co piszę, czy tylko wybierasz niektóre elementy? Odniosłem się do tematu niejednoznaczności i odpowiedziałem dlaczego, to nie ma sensu. Niejednoznaczności nie ma w przypadku statycznych importów pól i metod, bo importy są w tym wypadku ignorowane.

Michał Sikora napisał(a):
TomRiddle napisał(a):

Z polami i metodami statycznymi jakoś jest to rozwiązane i nie ma ambiguity. Czemu miałoby się nie dać z class?

Jest rozwiązane w ten sposób, że import jest ignorowany. Faktycznie, mogliby to dodać również dla class. Tylko bez sensu wydaje mi się dodawanie czegoś tylko po to, żeby móc to ignorować. Można się zastanawiać, czemu nie można wewnątrz klasy użyć po prostu class do pobrania java.lang.Class. Na to żadnego pomysłu nie mam. Podejrzewam, że głównie - bo szkoda zachodu dla takiego przypadku, kiedy alternatywa Foo.class wewnątrz Foo nie jest uciążliwa.

==========

TomRiddle napisał(a):

Chodzi mi o to:

class Foo {
  static int field;
  static int method() {} 

  public static void main() {
      // można 
      Foo.field
      Foo.method() 
      Foo.class
      field 
      method() 
      // nie można 
      class
  } 
} 

Czemu ten wyjątek?

Czyli nie pytasz o statyczne importowanie class, tylko o to, czemu nie ma konstrukcji Class<Foo> clazz = class;. Teoretycznie można tę konstrukcję odróznić od próby utworzenia klasy, ale byłaby to dodatkowa, niepotrzebna praca. W tym wypadku szczerze wydaje mi się, że najrozsądniejszą odpowiedzią jest "bo tak zdecydowali autorzy Javy". Aczkolwiek z chęcią dowiem się, jeżeli ktoś wie, czemu się nie da. :)

1
TomRiddle napisał(a):
cs napisał(a):

Ale class nie jest metodą, jak chcesz to podciągnąć pod statyczne importowanie metod? Dla przypomnienia wywołanie metody wymaga operatora (), class tego nie ma.

No i co z tego? To nie jest nic z czym parser by sobie nie poradził. Dla pół statycznych jakoś daje rade.

Parser nie ma tu nic do rzeczy. Można by tworzyć różne konstrukcje łamiące zasady jak wspomniany int.MAX_VALUE, ale ich nie ma,choć parser mógłby sobie z nimi poradzić. Twoje Class c = class; łamałoby wiele zasad, tylko po to, żeby zachować Twoją.

Po drugie jak często istnieje potrzeba, żeby klasa odwoływała się sama do siebie drogą refleksji, to pachnie jakąś schizofrenią. I być może to kolejny powód, dla którego drugie znaczenie class wymaga jawnej obecności nazwy klasy, a nie domyślnego kontekstu.

Po trzecie i chyba najważniejsze, co powinno zwrócić Twoje class, gdy odwołasz do niego w klasie anonimowej, albo wewnętrznej niestatycznej?

1 użytkowników online, w tym zalogowanych: 0, gości: 1