Сообщение Обязательный именованный параметр с проверкой при компиляции от 19.06.2023 16:27
Изменено 19.06.2023 16:27 vsb
Обязательное именованный параметр с проверкой при компиляции
У меня есть метод, которому я хочу передать несколько параметров. Типы у параметров могут совпадать. Я хочу это сделать таким образом, чтобы:
1. При изменении сигнатуры метода компилятор должен проверить все места вызова и убедиться, что они исправлены. К примеру добавление параметра.
2. При вызове нельзя незаметно перепутать два параметра с одинаковым типом.
По-человечески это делается, если есть фича именованные параметры. К примеру
[code=javascript]
function print({x, y}: {x: number, y: number}) {
console.log(x, y);
}
const x1 = 1, y1 = 2;
print({x: x1, y: y1});
[/code]
В Java такой фичи нет.
Если мы делаем просто вызов метода, то нарушается пункт 2. К примеру я могу написать test(y1, x1) и из этого будет совершенно не очевидно, что я написал ерунду.
Можно сделать объект с полями (parameter object). Но тут нарушается пункт 1. Если мы добавляем новое поле, то компилятор не проверит, что мы его инициализировали.
В голову приходит два варианта:
Вариант 1: избавиться от условия того, что типы у параметров могут совпадать. Т.е. завести типы-обёртки для каждого аргумента.
Вариант 2: сделать хитрый билдер.
Оба варианта слегка безумны. Даже с кодогенератором плодить класс на каждый параметр это чересчур.
Может я не вижу чего-то очевидного?
1. При изменении сигнатуры метода компилятор должен проверить все места вызова и убедиться, что они исправлены. К примеру добавление параметра.
2. При вызове нельзя незаметно перепутать два параметра с одинаковым типом.
По-человечески это делается, если есть фича именованные параметры. К примеру
[code=javascript]
function print({x, y}: {x: number, y: number}) {
console.log(x, y);
}
const x1 = 1, y1 = 2;
print({x: x1, y: y1});
[/code]
В Java такой фичи нет.
Если мы делаем просто вызов метода, то нарушается пункт 2. К примеру я могу написать test(y1, x1) и из этого будет совершенно не очевидно, что я написал ерунду.
Можно сделать объект с полями (parameter object). Но тут нарушается пункт 1. Если мы добавляем новое поле, то компилятор не проверит, что мы его инициализировали.
В голову приходит два варианта:
Вариант 1: избавиться от условия того, что типы у параметров могут совпадать. Т.е. завести типы-обёртки для каждого аргумента.
static class X {
final int x;
X(int x) {
this.x = x;
}
static X x(int x) {
return new X(x);
}
}
static class Y {
final int y;
Y(int y) {
this.y = y;
}
static Y y(int y) {
return new Y(y);
}
}
static void print(X x, Y y) {
System.out.println(x.x + " " + y.y);
}
public static void main(String[] args) {
int x1 = 1, y1 = 2;
print(x(x1), y(y1));
}Вариант 2: сделать хитрый билдер.
static class PrintArgs0 {
static PrintArgs0 printArgs() {
return new PrintArgs0();
}
PrintArgs1 x(int x) {
return new PrintArgs1(x);
}
}
static class PrintArgs1 {
private final int x;
PrintArgs1(int x) {
this.x = x;
}
PrintArgs y(int y){
return new PrintArgs(x, y);
}
}
static class PrintArgs {
private final int x;
private final int y;
public PrintArgs(int x, int y) {
this.x = x;
this.y = y;
}
}
static void print(PrintArgs args) {
System.out.println(args.x + " " + args.y);
}
public static void main(String[] args) {
int x1 = 1, y1 = 2;
print(printArgs().x(x1).y(y1));
}Оба варианта слегка безумны. Даже с кодогенератором плодить класс на каждый параметр это чересчур.
Может я не вижу чего-то очевидного?
Обязательный именованный параметр с проверкой при компиляции
У меня есть метод, которому я хочу передать несколько параметров. Типы у параметров могут совпадать. Я хочу это сделать таким образом, чтобы:
1. При изменении сигнатуры метода компилятор должен проверить все места вызова и убедиться, что они исправлены. К примеру добавление параметра.
2. При вызове нельзя незаметно перепутать два параметра с одинаковым типом.
По-человечески это делается, если есть фича именованные параметры. К примеру
[code=javascript]
function print({x, y}: {x: number, y: number}) {
console.log(x, y);
}
const x1 = 1, y1 = 2;
print({x: x1, y: y1});
[/code]
В Java такой фичи нет.
Если мы делаем просто вызов метода, то нарушается пункт 2. К примеру я могу написать test(y1, x1) и из этого будет совершенно не очевидно, что я написал ерунду.
Можно сделать объект с полями (parameter object). Но тут нарушается пункт 1. Если мы добавляем новое поле, то компилятор не проверит, что мы его инициализировали.
В голову приходит два варианта:
Вариант 1: избавиться от условия того, что типы у параметров могут совпадать. Т.е. завести типы-обёртки для каждого аргумента.
Вариант 2: сделать хитрый билдер.
Оба варианта слегка безумны. Даже с кодогенератором плодить класс на каждый параметр это чересчур.
Может я не вижу чего-то очевидного?
1. При изменении сигнатуры метода компилятор должен проверить все места вызова и убедиться, что они исправлены. К примеру добавление параметра.
2. При вызове нельзя незаметно перепутать два параметра с одинаковым типом.
По-человечески это делается, если есть фича именованные параметры. К примеру
[code=javascript]
function print({x, y}: {x: number, y: number}) {
console.log(x, y);
}
const x1 = 1, y1 = 2;
print({x: x1, y: y1});
[/code]
В Java такой фичи нет.
Если мы делаем просто вызов метода, то нарушается пункт 2. К примеру я могу написать test(y1, x1) и из этого будет совершенно не очевидно, что я написал ерунду.
Можно сделать объект с полями (parameter object). Но тут нарушается пункт 1. Если мы добавляем новое поле, то компилятор не проверит, что мы его инициализировали.
В голову приходит два варианта:
Вариант 1: избавиться от условия того, что типы у параметров могут совпадать. Т.е. завести типы-обёртки для каждого аргумента.
static class X {
final int x;
X(int x) {
this.x = x;
}
static X x(int x) {
return new X(x);
}
}
static class Y {
final int y;
Y(int y) {
this.y = y;
}
static Y y(int y) {
return new Y(y);
}
}
static void print(X x, Y y) {
System.out.println(x.x + " " + y.y);
}
public static void main(String[] args) {
int x1 = 1, y1 = 2;
print(x(x1), y(y1));
}Вариант 2: сделать хитрый билдер.
static class PrintArgs0 {
static PrintArgs0 printArgs() {
return new PrintArgs0();
}
PrintArgs1 x(int x) {
return new PrintArgs1(x);
}
}
static class PrintArgs1 {
private final int x;
PrintArgs1(int x) {
this.x = x;
}
PrintArgs y(int y){
return new PrintArgs(x, y);
}
}
static class PrintArgs {
private final int x;
private final int y;
public PrintArgs(int x, int y) {
this.x = x;
this.y = y;
}
}
static void print(PrintArgs args) {
System.out.println(args.x + " " + args.y);
}
public static void main(String[] args) {
int x1 = 1, y1 = 2;
print(printArgs().x(x1).y(y1));
}Оба варианта слегка безумны. Даже с кодогенератором плодить класс на каждый параметр это чересчур.
Может я не вижу чего-то очевидного?