Подтвердить что ты не робот

Java generics с "семантикой", возможно ли это?

Сначала извиняюсь, если я использую неправильный термин, выбрав слово "семантика".

Я большой поклонник дженериков в Java по всем очевидным причинам. Это очень помогает мне, когда я работаю с огромным количеством нечетных битов кода, и мне часто приходится возвращаться к старым вещам. Сегодня я столкнулся с ошибкой классической ошибки, которую я, вероятно, не написал бы в предродовые дни, - они сделали меня немного ленивым.

Я хотел бы знать, есть ли языковая функция, либо на Java, либо, возможно, как аналогичная концепция на других языках, которая берет на себя безопасность типов дженериков и расширяет ее до своего рода семантической безопасности. В частности, я хочу помочь избежать ошибок, возникающих из-за неправильной установки.

Простой пример:

Map<String, String> myMap = new HashMap<String, String>();
String myKey = "key";
String myVal = "value";
myMap.put(myVal, myKey);

Какой компилятор не поймает. Я мог бы subclass String сделать обертками, чтобы дать мне тип Key и тип Value, я полагаю. Я могу назвать свои переменные, чтобы указать их использование (как я сделал в этом примере). Что еще?

Итак, мои вопросы:

  • из академического интереса, что называется этой концепцией и какие языки имеют эту функцию?
  • В отсутствие какой-либо такой языковой функции, каковы наилучшие методы, чтобы избежать такой ошибки?

Спасибо

4b9b3361

Ответ 1

Я всегда использовал карты, которые имеют два разных типа для ключа и значения, никогда не имеют одинаковых типов. Я предполагаю, что есть моменты, когда вы хотели бы использовать один и тот же тип для ключа и значения, как в вашем примере. Я не могу думать о каких-либо языках с моей головы, которые имеют эту функцию.

На самом деле я использовал Clojure до и для карт, он использует ключевое слово для ключа, которое выглядит как :key, а затем значение - это все, что угодно. Это делает его более ясным, но теперь я занимаюсь функциональным программированием, и это не вопрос, который вы задавали. Проверьте Lisp -подобные языки.

Я думаю, что это просто случай, когда они не смешиваются, Java, конечно, не может обеспечить такой контроль.

Лучшим советом было бы использовать разные типы для ключа и значения, чтобы компилятор мог обнаружить ошибку типа, или явно указывать переменные ключа и значения, как вы это делали.

Ответ 2

Вы не можете подклассифицировать String. Однако вы можете создавать свои собственные классы и использовать их. Например, если вы сопоставляете Лица с Ролями, вы можете определить Person like

class Person {
  String id;
  String firstName;
  String lastName;
   ...
}

и роль, подобная

class Role {
    int id;
    String name;
}

(Обратите внимание, что они должны определить метод equals и hashcode)

и иметь сопоставление от человека к роли типа:

Map<Person, Set<Role>> myMap = new HashMap<Person, Set<Role>>();

чтобы система типа применяла то, что вы можете поместить где (в отличие от того, чтобы иметь карту строк для наборов ints). Не уверен, что это называется, но "Доменные объекты" и "Абстрактные типы данных" кажутся взаимосвязанными.

В отсутствие проверки типов резервное копирование - это модульные тесты.

Ответ 3

Вы можете использовать более обширную систему типов, избегая использования одного и того же типа в списках параметров.

то есть.

Map<Key, Value> myMap = new HashMap<Key, Value>();
Key myKey = // some key
Value myVal = // some value
myMap.put(myVal, myKey); //compiler error

На каком-то уровне вам нужно объяснить концепции и то, как они взаимодействуют с операциями, чтобы проверить язык на что-либо, заинтересованы в том, есть ли альтернативные подходы там.

Ответ 4

Я не знаю ни одной языковой концепции, которая поймала бы это. В основном то, что вы просите, это компилятор для чтения ума. то есть.

  • Вы хотите создать карту пар.
  • Вы хотите (предположительно) использовать любое имя переменной по вашему выбору.
  • Вы хотите, чтобы компилятор обнаружил, что вы передали аргументы в неправильном порядке.

Моя единственная мысль состоит в том, что язык может наложить синтаксическое ограничение, чтобы имитировать требуемое семантическое ограничение. Например, это может потребовать, чтобы вы назвали переменные, которые должны использоваться в качестве ключей "key_somename_", а также для значений. Немного улучшения, но это скорее ограничивает программиста.

Если вы действительно беспокоитесь об этом, вы можете в Java расширять Map, чтобы принимать только типы, реализующие фиктивный "ключ", и создавать подтипы, которые реализуют этот интерфейс каждый раз, когда вы хотите использовать класс ключей.

Ответ 5

Это очень дерьмово, но оно работает:

public static <K extends String,V extends String> void test() {
  K key = (K) "foo";
  V val = (V) "bar";
  Map<K,V> map = new HashMap<K,V>();
  map.put(key,val);
}

Теперь это немного интереснее:

// The whole code is using type parameters like this:
public static <K extends String,V extends String> void test(K key, V value) {
  Map<K,V> map = new HashMap<K,V>();
  map.put(key,val);
}

// At the end, use the real type (K=String, V=String);
public static void main(String[) args) {
  test<String,String>("foo","bar");
};