Если мы делаем просто вызов метода, то нарушается пункт 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));
}
Оба варианта слегка безумны. Даже с кодогенератором плодить класс на каждый параметр это чересчур.
Здравствуйте, ·, Вы писали:
·>Здравствуйте, vsb, Вы писали:
·>Завернуть в параметр-интерфейс:
· ·>Такое более привычно с т.з. дизайна, хоть и многословно.
При отсутствии именованных параметров, обычно используют билдеры (особенно, в Java) и прокси-типы (newtypes). Неужели озвученный параметр-интерфейс — привычное дело в мире сабжа?
Re[3]: Обязательный именованный параметр с проверкой при ком
Здравствуйте, flаt, Вы писали:
F>·>Такое более привычно с т.з. дизайна, хоть и многословно. F>При отсутствии именованных параметров, обычно
Он же написал почему это не работает для его требований:
F>используют билдеры (особенно, в Java)
не будет compile-time ошибки при добавлении нового парама.
F>и прокси-типы (newtypes).
Чем поможет-то? func(1, 2) => func(new NewType(1, 2))?! Имена-то где? Ну или "Вариант 1" выше, который тоже не сахар.
F>Неужели озвученный параметр-интерфейс — привычное дело в мире сабжа?
Если нужно потребовать от клиентского кода предоставлять сразу пачку именованных символов — то да.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали:
F>>и прокси-типы (newtypes). ·>Чем поможет-то? func(1, 2) => func(new NewType(1, 2))?! Имена-то где? Ну или "Вариант 1" выше, который тоже не сахар.
никто обычно функции c константами не вызывает. Существует одно место в коде, где значение связывается с типом и дальше по call stack невозможно ошибиться
NewType1 val1 = new NewType1(1);
NewType2 val2 = new NewType2(2);
...
func(val1, val2);
Re[5]: Обязательный именованный параметр с проверкой при ком
Здравствуйте, sergii.p, Вы писали:
F>>>и прокси-типы (newtypes). SP>·>Чем поможет-то? func(1, 2) => func(new NewType(1, 2))?! Имена-то где? Ну или "Вариант 1" выше, который тоже не сахар.
SP>никто обычно функции c константами не вызывает.
Пара булевых флагов и вот уже путаница. Т.е. достаточно иметь более одного параметра одного типа.
SP>Существует одно место в коде, где значение связывается с типом
Если ты предлагаешь искусственно объявлять уникальный тип для каждого параметра, то это и есть упомянутые выше прокси типы, которые отстой.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[6]: Обязательный именованный параметр с проверкой при ком
Здравствуйте, sergii.p, Вы писали:
SP>·>Пара булевых флагов и вот уже путаница. Т.е. достаточно иметь более одного параметра одного типа. SP>булевы параметры — это триггер на code review обычно. Их можно заменить enum. И внезапно повысили чатаемость кода и усилили систему типов.
Да это же пример. Вот ещё код, с правильными типами, а толку?
Receipt transfer(Account from, Account to, Money amount, Money fee);
...
...
Account to = getAccountSeller();
Account from = getAccountBuyer();
Money fee = calcFee();
Money amount = getOrderPrice();
var receipt = transfer(to, from, fee, amount);
send(receipt);
SP>·>прокси типы, которые отстой. SP>конструктивная аргументация...
Предложи конструктивно как переписать правильно, чтобы ошибка была очевидна.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали:
·>Предложи конструктивно как переписать правильно, чтобы ошибка была очевидна.
// Общая часть. Каждый раз переписывать не надоclass NewType<T> {
T value;
public T to_underlying() {
return value;
}
public NewType(T obj) {
this.value = obj;
}
// можно ещё переопределить методы toString, hashCode, кому надо
}
// Каждый тип объявлять немного многословно. Не хватает typedef конструкции в языкеclass XType extends NewType<Integer> {
XType(int val) { super(val); }
}
class YType extends NewType<Integer> {
YType(int val) { super(val); }
}
class HelloWorld {
static void print(XType x, YType y) {
//...
}
public static void main(String[] args) {
var x = new XType(3);
var y = new YType(42);
print(x, y);
//print(y, x); //Error YType cannot be converted to XType
}
}
Здравствуйте, sergii.p, Вы писали:
SP>·>Предложи конструктивно как переписать правильно, чтобы ошибка была очевидна. SP>class XType extends NewType<Integer> {
Это "вариант 1" у топик-стартера в первом сообщении и его мнение "плодить класс на каждый параметр это чересчур". . Зачем ты это всё рассказал-то?
Кстати, вместо твоей колбасы с генериками давно можно просто писать record XType(int value){}.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[10]: Обязательный именованный параметр с проверкой при ком
Здравствуйте, ·, Вы писали:
·>Это "вариант 1" у топик-стартера в первом сообщении и его мнение "плодить класс на каждый параметр это чересчур". .
у ТС класс занимал 10 строчек. Тут 3. Мне показалось что это основной критерий почему нельзя "плодить класс на каждый параметр".
·>Зачем ты это всё рассказал-то?
ну ты ведь попросил, я рассказал.
·>Кстати, вместо твоей колбасы с генериками давно можно просто писать record XType(int value){}.
возможно. java — не мой основной язык. Если это работает, тем более идиома нового типа будет актуальна.
Re[11]: Обязательный именованный параметр с проверкой при ко
Здравствуйте, sergii.p, Вы писали:
SP>·>Это "вариант 1" у топик-стартера в первом сообщении и его мнение "плодить класс на каждый параметр это чересчур". . SP>у ТС класс занимал 10 строчек. Тут 3. Мне показалось что это основной критерий почему нельзя "плодить класс на каждый параметр".
Потому что ты смухлевал, удалив переводы строк и static метод для конструирования. А по сути ровно то же.
Ты предложил так
class XType { final int val;
XType(int val) { this.val=val; }
}
Даже короче и с боксингом примитивов проблемы нет.
SP>·>Зачем ты это всё рассказал-то? SP>ну ты ведь попросил, я рассказал.
Ну это уже было в стартовом сообщениии. А вопрос был об альтернативах.
SP>·>Кстати, вместо твоей колбасы с генериками давно можно просто писать record XType(int value){}. SP>возможно. java — не мой основной язык. Если это работает, тем более идиома нового типа будет актуальна.
У этой идиомы и другие недостатки. Например, нет никакого способа запретить таки использовать один и тот же тип в разных параметрах. При копи-пастах код начнёт расползаться.
Было
Receipt transfer(AccountFrom from, AccountTo to, MoneyAmount amount, MoneyFee fee);