Почему не распространен такой оператор?

luna89

Хочу оператор, который из структуры и поля делает "линзу" - пару из геттера и сеттера. Например, если есть тип:

type Person = {
name: string;
age: int;
}

и переменная этого типа:

p: Person;

то
p^name - это линза структуры p в поле name. Она имеет тип:

type Lens<string> = {
get: => string,
set: (string) => void
}

Оператор нужен для типизированного датабиндинга. Например, в поле ввода для редактирования имени можно передать линзу:

Person p = new Person('Alice',20);
Input input = new Input(p^name);

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

parseInt: (Lens<Maybe<Integer>>) => Lens<String>

чтобы потом сделать поле для ввода возраста пользователя:

Person p = new Person('Alice',20);
Input input = new Input(parseInt(p^age;

Из-за отсутствия такого удобного оператора в java появились конвенции о геттерах и сеттерах, которые, во-первых, работают через reflection и в силу этого имеют ряд недостатков (отсутствие типизации например а во-вторых, с ними неудобно работать - я не могу передать куда-то геттер и сеттер как первоклассный объект.
Что печалит, в новых языках, таких как тайпскрипт, тянут идиотские геттеры и сеттеры как в C#.

Toma90

>> Из-за отсутствия такого удобного оператора в java появились конвенции о геттерах и сеттерах,
Это, конечно, ошибочное утверждение.
>> которые, во-первых, работают через reflection и в силу этого имеют ряд недостатков (отсутствие типизации например
Геттеры/сеттеры можно вызывать, например, at compile time.
>> а во-вторых, с ними неудобно работать - я не могу передать куда-то геттер и сеттер как первоклассный объект.
Это тоже ошибочное утверждение. Например, в Java 8 можно
Person p = ...
Lens<String> pNameLens = Lens.of(p::getName, p::setName);

interface Lens<T> {

static <T> Lens<T> of(Supplier<T> getter, Consumer<T> setter) {
return new Lens<> {
public T get { return getter.get; }
public void set(T t) { setter.accept(t); }
};
}

T get;
void set(T t);

}

Papazyan

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

apl13

А ты не про делегаты еще какие-нибудь, а?
template<class C, typename F> struct Lens {
typedef Lens This;
typedef C Class;
typedef F RetVal;
typedef RetVal Class::*Field;
Lens(Field f): f(f) {}
Lens &operator=(Field that) { return f = that, *this; }
RetVal get(Class const &obj) { return obj.*f; }
RetVal set(Class &obj, RetVal const &val) { return obj.*f = val; }
private:
Field f;
};
template<class C, typename F> inline Lens<C, F> lens(F C::*f) { return Lens<C, F>(f); }
#define LENS(field) lens(&field)
struct C { int x; };
C c = {42};
#include <iostream>
{
using namespace std;
cout << LENS(C::x).get(c) << endl;
}

(Можно и ссылку на объект внутри хранить, но лучше расшаренную, а они искаропки только в 11-х плюсах появились.)

yroslavasako

я не могу передать куда-то геттер и сеттер как первоклассный объект.
я просто делаю на лету из них замыкание. Благо в скале его делать очень просто
methodName _

А если хочется настоящих линз - юзай shapeless и scalaz. Всё типобезопасно и даже без рефлексии.

6yrop

В C# есть типизированное решение того, что ты хочешь.
Оставить комментарий
Имя или ник:
Комментарий: