Я работал над созданием своего собственного статически типизированного языка, когда понял, что может быть невозможно различить выражение с помощью оператора <
и аргумент типа для класса или метода.
Основная причина этого заключается в том, что, как и в C #, классы не обязательно должны быть объявлены вперед перед использованием, поэтому, когда идентификатор анализируется после <
, это может быть либо выражение типа valueA < valueB
, либоэто может быть аргумент типа, например valueA<valueB>
.
Итак, я подумал, может быть, если есть закрывающий >
, то его можно проанализировать как аргумент типа, но потом я вспомнил, что мне нужен мой языкиметь перегрузку операторов, поэтому выражения типа valueA < valueB > (valueC)
могут быть совершенно корректными.
Я решил поэкспериментировать с другими языками и обнаружил, что C # наиболее похож на язык, который я пытался создать, и явозможно, сломал его.
Выражение foo < bar > (2)
в приведенном ниже коде должно быть совершенно допустимым выражением из-за класса остроумияh перегружены операторы <
и >
.
Насколько мне известно, выражение должно быть проанализировано как (foo < bar) > (2)
, но вместо этого я получаю сообщение об ошибке "The variable 'foo' cannot be used with type arguments."
Чтобы доказать, что это выражение если будет действительным, я щелкнул по знакам <
и >
, чтобы выражение выглядело как foo > bar < (2)
, и эта программа скомпилировала и распечатала в точности то, что вы ожидаете, MainClass+baz
.
В этом конкретном примере компилятор, вероятно, мог бы это выяснить, поскольку он знает, что foo
является переменной, и мог бы предположить, что <
означает выражение, но если бы foo был статическим членом другого класса, тоне может быть никакого различия между выражением <
и аргументом типа.
using System;
class MainClass {
public static void Main (string[] args) {
baz foo = new baz();
baz bar = new baz();
// perfectly valid expression, results in error: The variable `foo' cannot be used with type arguments
Console.WriteLine(foo < bar > (2));
}
class baz {
public static baz operator<(baz l, baz r) {
return l;
}
public static baz operator>(baz l, baz r) {
return l;
}
public static baz operator<(baz l, int r) {
return l;
}
public static baz operator>(baz l, int r) {
return l;
}
}
public String toString() {
return "baz";
}
}
Мой вопрос: как решить эту проблему в компиляторе C # и других языках?
Я вижу несколько вариантов:
- Сообщить об ошибке в неоднозначных ситуациях
- Возможно, есть еще какой-то контекст, который можно использовать для устранения этой неоднозначности
- C # по существу не работает, и мы должны разработать новый синтаксис для аргументов типа в будущих языках. Если да, то как это должно выглядеть?
Может быть, есть какой-то стандарт на это, но я думаю, что принятие этого было бы просто халатностью, и мы должны по крайней мере пойти с вариантом 1.