Re[35]: Inline records
От: Pavel Dvorkin Россия  
Дата: 19.10.09 06:14
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Особенно если тебе в цикле надо раскидать работу по множеству потоков.


На здоровье

основной поток

A a[N];
for (int i = 0; i < N; i++) beginthreadex(a+i);
while(не знаю что)
{
for (int i = 0; i < N; i++)
{
заполняем а[i]
SetEvent(hEventRequest[i])
}
WaitForMultipleObjects(N, hEventResponse, AND); // можно и что-то похитрее, например, ждать по OR, и как дождались — дать новое задание тому, кого дождались.
}


рабочие потоки

threadfunc(void* p)
{
A* pa = (A*) p;
while(не знаю что)
{
WaitForSingleObject;
// что-то делем c pa
SetEvent
}

А суть одна — что ни делай, переменная A (массив А) стать невалидной не может, так что указатели все тоже валидны.
With best regards
Pavel Dvorkin
Re[37]: Inline records
От: Pavel Dvorkin Россия  
Дата: 19.10.09 06:20
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Напиши таким образом реальный код, который например распараллеливает суммирование массива чисел на N потоков.


Да бога ради. Возьми мой пример

http://rsdn.ru/forum/philosophy/3574195.1.aspx
Автор: Pavel Dvorkin
Дата: 19.10.09


и замени в нем передачу в поток a+i на передачу адреса того участка, который нужно отсуммировать данному потоку, длины его и адрес переменной для суммы. Каждый поток получит свой кусок и найдет его сумму. Остается дождаться их всех и просуммировать суммы.

Кстати, это я делал примерно год назад, когда обсуждали вычисление сумм по столбцам или строкам пикселей окна.
With best regards
Pavel Dvorkin
Re[38]: ссылка с моим кодом и твоим ответом
От: Pavel Dvorkin Россия  
Дата: 19.10.09 06:36
Оценка:
http://www.rsdn.ru/forum/philosophy/3159884.1.aspx
Автор: gandjustas
Дата: 01.11.08


ну и далее по треду.
With best regards
Pavel Dvorkin
Re[32]: рандеву (Inline records)
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 19.10.09 07:11
Оценка: +1
Здравствуйте, Pavel Dvorkin, Вы писали:

G>>Да ты че?

G>>Если ты не понял, то указатель A* data в потоке станет ни разу не валидным после завершения функции launch.
PD>О господи! Сил уже нет!

Я поменял subject, а то мы далеко ушли от исходной темы.

PD>Ты хоть пойми, что такое рандеву! Внутри launch стоит wait_event(pd.thanks); А в потоковой функции есть set_event(pd->thanks);, который и означает, что работа с этим A* закончена.

PD>До тех пор, пока не вызвали в потоке set_event(pd->thanks), переменная A a из основного потока существует, так как выход из launch невозможен.И как только дождемся в основном потоке — только теперь эта переменная может помереть.

Это плохое решение по нескольким причинам:

1. Малейшая ошибка в реализации launch() в более-менее сложном случае (а не передаче одного параметра) приведёт к тому, что launch() может вылететь с исключением. В этом случае другие треды, уже запущенные, будут обращаться к невалидной памяти, соответственно с непредсказуемыми последствиями.

Поэтому твой код резко противоречит стилю C++, в котором надо сейчас писать так, чтобы вышибание табуретки из-под ног в любой момент не приводило к общему завису;))

2. Ты останавливаешь тот тред, в котором launch(), целиком внутри неуправляемой функции. Если тебе потребуется его прервать, ты не сможешь этого сделать.

3. Точно так же, ты не в состоянии отреагировать без внешних костылей на завис или слёт другого треда перед тем, как тебе сказали thanks (только не говори, что это невозможно;)) — будешь просто висеть в ожидании события.

Таким образом, твой метод, даже если работает, должен быть квалифицирован как немасштабируемый хак, пригодный только для тепличных случаев идеальной работы. Напротив, вариант аллоцировать каждому кусок устойчивой (по сравнению с твоим стеком) памяти и отдать в пользование (в идеале — да, чтобы тут же сказал free) не страдает подобными ограничениями.
The God is real, unless declared integer.
Re[35]: Inline records
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 19.10.09 07:14
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>Дождемся чего? Завершения потока?

PD>>ивента! Ясно же написано — wait_event(pd.thanks);
G>>>Иначе придется скопировать данные из A еще куда-либо.
PD>>Зачем ? Они уже обработаны. Поток продолжает свою деятельность без обращения к ним.
G>То есть на время обработки А (фактически где существует обращение к А) launch будет заблокирован?

Нет, смотри оригинальный пример. PD сейчас сам запутался. Изначально событие было занято только на момент, пока новый тред не подтвердил приём данных. Это более-менее обычный приём для ряда ситуаций. Сейчас же он пытается "на ходу" развернуть это на пул потоков с ожиданием любого из, а это уже совсем другая ситуация.

PD>>Это точно. Бывает лишь элементарное непонимание!

PD>>См. пример http://rsdn.ru/forum/philosophy/3574170.1.aspx
Автор: Pavel Dvorkin
Дата: 19.10.09

G>Ты вообще представляешь как это медленно работать будет? Особенно если тебе в цикле надо раскидать работу по множеству потоков.

Не так уж и медленно. Скорее наоборот — быстро:) Другой вопрос, что я не понимаю смысл применения системного вызова и пинания этим ядра там, где malloc/free сработают быстрее и не требуя (в общем случае) переключения контекста вверх.
The God is real, unless declared integer.
Re[7]: Inline records
От: kochetkov.vladimir Россия https://kochetkov.github.io
Дата: 19.10.09 07:45
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, kochetkov.vladimir, Вы писали:


VD>>>Ну, и поддерживается ли для типа record (если он существует) структурная идентичность? Ну, когда две независимо созданные записи идентичны при условии, что идентичны значения и имена полей.


KV>>Во втором варианте кода — да, поддерживается:


VD>Здорово!

VD>Но все же здесь получается, что возвращаются экземпляры класса. Идентичность для них достигается путем переопределения метода сравнения. Не получится ли так, что в некотором контексте объекты все же окажутся не равны?

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

1. Необходимо еще переопределить метод __ne__() (проверка на неравенство, для симметричности операции), либо вместо обоих один метод __cmp__() (сравнение)
2. Приведенные в примерах рекорды нельзя использовать в качестве ключей в словарях (хэш-таблицах), т.к. метод __hash__() они унаследуют от тупла, а следовательно у двух записей с одинаковыми значениями полей, но с разными названиями будет одинаковый хэш.

VD>ЗЫ


VD>А вообще, скрипты основанные на модели прототипного ООП и мета-классов весьма гибки в области метапрограммирования. Но платой за это является производительность. Ведь такие вот выкрутасы уже никак не оптимизируешь. Тут само представление объекта должно быть хэш-таблицей. Иначе фокус не пройдет.


Это да

VD>Я же рассуждал о статически типизированных языках в которых все определяется декларацией.

VD>Собственно создать такой перепаковщик можно и на базе макросов того же немерле. Проблема в том, что это не очень красивое решение, так как операция сравнения будет весьма не шустрой (придется сравнивать имена и значения полей в рантайме), и не всегда корректной, так как порой важен фактический тип, а не наличие у него операции сравнения. Скажем при передаче в качестве параметра.

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

[Интервью] .NET Security — это просто
Автор: kochetkov.vladimir
Дата: 07.11.17
Re[36]: Inline records
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 19.10.09 07:50
Оценка:
Здравствуйте, netch80, Вы писали:

N>Здравствуйте, gandjustas, Вы писали:


G>>>>Дождемся чего? Завершения потока?

PD>>>ивента! Ясно же написано — wait_event(pd.thanks);
G>>>>Иначе придется скопировать данные из A еще куда-либо.
PD>>>Зачем ? Они уже обработаны. Поток продолжает свою деятельность без обращения к ним.
G>>То есть на время обработки А (фактически где существует обращение к А) launch будет заблокирован?

N>Нет, смотри оригинальный пример. PD сейчас сам запутался. Изначально событие было занято только на момент, пока новый тред не подтвердил приём данных. Это более-менее обычный приём для ряда ситуаций. Сейчас же он пытается "на ходу" развернуть это на пул потоков с ожиданием любого из, а это уже совсем другая ситуация.

А что значит "прием данных"?
Если использовать только указатель, то launch не должна завершаться пока поток работает с этими данными.
Если же данные копируются, то это лишние затраты.
Затраты конечно маленькие по сравнению с созданием потока, но общая картина от этого лучше не становится.
Re[8]: Inline records
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.10.09 11:45
Оценка: +1
Здравствуйте, kochetkov.vladimir, Вы писали:

KV>В голове крутится мысль, что можно уйти от необходимости проверок в рантайме, если имена полей представлять не строкой, а одноименным типом, который будет генериться средствами мета-программирования, но возможно это — заблуждение от недостаточного владения немерлом, а не реальное решение


С типом проблема в том, что в донете нет структурной идентичности. И утиной типизации тоже нет. Так что два, с виду, одинаковых объекта в некотором месте будут не совместимы.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[33]: рандеву (Inline records)
От: Pavel Dvorkin Россия  
Дата: 19.10.09 12:30
Оценка:
Здравствуйте, netch80, Вы писали:

N>Я поменял subject, а то мы далеко ушли от исходной темы.


Честно говоря, мне давно уже надоела вся эта дискуссия. Черт меня угораздил ввязаться в нее. Началось все с безобидного (как мне казалось тогда) ответа samius

http://rsdn.ru/forum/philosophy/3571479.1.aspx
Автор: Pavel Dvorkin
Дата: 16.10.09


где я вымолвил слово в защиту ООП для автоматических переменных, дав кусок из стандарта С++. А дальше в дело вмешался gandjustas, а я , вместо того, чтобы просто проигнорировать его опус, решил ему эту ссылку на стандарт привести, ну и пришлось в итоге доказывать, что Волга впадает в Каспийское море


N>Это плохое решение по нескольким причинам:


Это не плохое и не хорошее решение. Это (сообщение КодТ) вообще не решение, а просто псевдокод, иллюстрирующий тот факт, что автоматические переменные вполне можно передавать куда угодно и как угодно, брать на них указатели и передавать их куда угодно и как угодно. Одно лишь требование должно выполняться — указатель не должен жить (или по крайней мере использоваться) дольше , чем то, на что он показывает. И только. И правило это применимо не только к автоматическим объектам, но и к объектам, выделяемым в куче.

В этом смысле вот такой код

int main()
{
char a[100], *p = a;
// делай с a и p что хочешь, передавай их хоть в потоки, хоть куда угодно.
// если запустили потоки — дождаться завершения их всех
}


совершенно корректен, потому что a и p имеют одинаковое время жизни, иными словами, пока не выйдем на } в main, массив жив и указатели на него валидны.

Равным образом можешь придумать примеры, где это будет неверно.

И именно для демонстрации этого приницпа и был написан КодТ этот пример. Для этого, и ничего больше.

А стоит ли делать именно так или же не стоит — от задачи зависит. Где-то стоит так, где-то — иначе.

Вот, собственно , и все. А обсуждать плюсы или минусы этого конкретного примера я не буду, так как к исходному вопросу это отношения не имеет, а дискутировать специально на эту тему я не хочу. Да и не автор я этого примера. КодТ просто показал, что такое возможно. Больше ничего.

N>1. Малейшая ошибка в реализации launch() в более-менее сложном случае (а не передаче одного параметра) приведёт к тому, что launch() может вылететь с исключением. В этом случае другие треды, уже запущенные, будут обращаться к невалидной памяти, соответственно с непредсказуемыми последствиями.

N>Поэтому твой код резко противоречит стилю C++, в котором надо сейчас писать так, чтобы вышибание табуретки из-под ног в любой момент не приводило к общему завису)

Без комментариев, ибо длинная это песня.

N>2. Ты останавливаешь тот тред, в котором launch(), целиком внутри неуправляемой функции. Если тебе потребуется его прервать, ты не сможешь этого сделать.


Во-первых, у нас все функции неуправляемые А во-вторых, посмотри мой пример с SignalObjectAndWait. Внутри нее мне прерывать совершенно незачем.

N>3. Точно так же, ты не в состоянии отреагировать без внешних костылей на завис или слёт другого треда перед тем, как тебе сказали thanks (только не говори, что это невозможно) — будешь просто висеть в ожидании события.


Верно, но какое отношение это имеет к передаче автоматических переменных ? Решений много, обсуждать сейчас не буду.

N>Таким образом, твой метод, даже если работает, должен быть квалифицирован как немасштабируемый хак


Не согласен, так как здесь нет никаких действий, противоречащих стандарту языка.


>пригодный только для тепличных случаев идеальной работы. Напротив, вариант аллоцировать каждому кусок устойчивой (по сравнению с твоим стеком) памяти и отдать в пользование (в идеале — да, чтобы тут же сказал free) не страдает подобными ограничениями.


Я что-то не понял, почему это решит проблемы 3 или 2 ? Да и 1 тоже. Я ведь с таким же успехом могу по ошибке в launch освободить их раньше, чем это будет надо.

Вот сравни

int main()
{

int a[10][20];

потокам передаем свои строки, т.е. a[i] из стека
ждем завершения всех потоков
}

и

int main()
{

int *a[10];
for (int i = 0; i < 10; i++)
a[i] = new int[10];
// ты уж мне прости автоматический массив указателей, но передаю я все же указатель на память, выделенную в куче. Если простить не можешь — помести их в другое место, но оставь их 10 штук
потокам передаем свои строки, т.е. a[i] из кучи.
ждем завершения всех потоков
}

В чем разница ? И почему в первом случае память неустойчива, а во втором устойчива ? Скорее наоборот, ошибку сделать легче

int main()
{

int *a[10];
for (int i = 0; i < 10; i++)
a[i] = new int[10];

потокам передаем свои строки, т.е. a[i] из кучи.
и не нужны мне вроде бы эти массивы больше...
for (int i = 0; i < 10; i++)
delete a[i];
ждем завершения
}

И вот она готова! Попробуй эту ошибку в первом примере сделать ! То есть попробуй сделать хоть один a[i] невалидным.
With best regards
Pavel Dvorkin
Re[36]: Inline records
От: Pavel Dvorkin Россия  
Дата: 19.10.09 12:49
Оценка:
Здравствуйте, netch80, Вы писали:

N>Здравствуйте, gandjustas, Вы писали:


N>Нет, смотри оригинальный пример. PD сейчас сам запутался.


Отчасти да. Увы, КодТ сделал там ошибку, из-за нее все и пошло

A data = &(A*)(pd->data)

Так быть не может. Либо

A data = *(A*)(pd->data)

и тогда копируем, верно, и ты прав

>Изначально событие было занято только на момент, пока новый тред не подтвердил приём данных. (т.е скопировал — PD)


либо

A* data = (A*)(pd->data)

как модифицировал я, и тогда надо быстро обработать data, и просигнализировать, что он мне больше не нужен (что я и предложил).

Оба решения корректны.



>Это более-менее обычный приём для ряда ситуаций. Сейчас же он пытается "на ходу" развернуть это на пул потоков с ожиданием любого из, а это уже совсем другая ситуация.


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

N>Не так уж и медленно. Скорее наоборот — быстро Другой вопрос, что я не понимаю смысл применения системного вызова и пинания этим ядра там, где malloc/free сработают быстрее и не требуя (в общем случае) переключения контекста вверх.


Что-то просто не понял. Извини, но после десяти часов занятий (сегодня) я уже плохо соображаю. Я предлагаю массив в стеке. Ты предлагаешь выделить память в куче. В этом я разницу вижу. Дальше я плохо понимаю. Быстрее чего malloc/free сработает — выделения в стеке ? Куда и какой контекст я переключаю, а ты нет ?
With best regards
Pavel Dvorkin
Re[20]: Inline records
От: Трурль  
Дата: 20.10.09 14:30
Оценка: 10 (1)
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, samius, Вы писали:


S>>Скорее

S>>
S>>POINTS points = MakePoints(10);
S>>POINT p = GetPoint(points, 10);
S>>

S>>При такой инкапсуляции мы можем потерять размер записи. Здесть POINTS и POINT — это лишь хэндлы.

PD>Если POINT и POINTS — это только хендлы — пожалуйста, дай мне их описание. typedef или #define. И ты сразу поймешь, что кроме void* у тебя ничего нет — типов-то нет. И никто мне не помешает написать


PD>points = p;


PD>и даже предупреждения не будет, а потом все с ума сойдут.


typedef struct POINT* POINT;
typedef struct POINTS* POINTS;
POINTS MakePoints(int);
POINT GetPoint(POINTS, int);
void BadUasge()
{
  POINTS points = MakePoints(10);
  POINT p = GetPoint(points, 10);
  points = p;
}


warning C4133: '=' : incompatible types — from 'struct POINT *' to 'struct POINTS *'

Re[21]: Inline records
От: Pavel Dvorkin Россия  
Дата: 21.10.09 05:14
Оценка:
Здравствуйте, Трурль, Вы писали:

Т>
Т>typedef struct POINT* POINT;
Т>typedef struct POINTS* POINTS;
Т>POINTS MakePoints(int);
Т>POINT GetPoint(POINTS, int);
Т>void BadUasge()
Т>{
Т>  POINTS points = MakePoints(10);
Т>  POINT p = GetPoint(points, 10);
Т>  points = p;
Т>}
Т>



1>e:\9869\1111.cpp(1) : error C2040: 'POINT' : 'POINT *' differs in levels of indirection from 'POINT'

1>e:\9869\1111.cpp(2) : error C2040: 'POINTS' : 'POINTS *' differs in levels of indirection from 'POINTS'
1>e:\9869\1111.cpp(7) : error C2079: 'points' uses undefined struct 'POINTS'
1>e:\9869\1111.cpp(7) : error C2440: 'initializing' : cannot convert from 'POINTS' to 'int'
1> Source or target has incomplete type
1>e:\9869\1111.cpp(8) : error C2079: 'p' uses undefined struct 'POINT'
1>e:\9869\1111.cpp(8) : error C2664: 'GetPoint' : cannot convert parameter 1 from 'int' to 'POINTS'
1> Source or target has incomplete type
1>Build log was saved at "file://e:\9869\Debug\BuildLog.htm"
1>9869 — 6 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
With best regards
Pavel Dvorkin
Re[22]: Inline records
От: Трурль  
Дата: 21.10.09 09:03
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

>1>e:\9869\1111.cpp(1) : error C2040: 'POINT' : 'POINT *' differs in levels of indirection from 'POINT'


Вроде, речь шла о си.
Re[23]: Inline records
От: Pavel Dvorkin Россия  
Дата: 21.10.09 09:16
Оценка:
Здравствуйте, Трурль, Вы писали:

Т>Здравствуйте, Pavel Dvorkin, Вы писали:


>>1>e:\9869\1111.cpp(1) : error C2040: 'POINT' : 'POINT *' differs in levels of indirection from 'POINT'


Т>Вроде, речь шла о си.


Сорри. Верно.

Ты сделал примерно то же, что в режиме #define STRICT делается в windows.h. Хендлы в теории — это просто целые числа, но если их реализовать как unsigned int (или long), то можно будет писать hPen = hBrush. Поэтому они там реализованы как указатели на структуры разных типов.
With best regards
Pavel Dvorkin
Re[2]: Inline records
От: kochetkov.vladimir Россия https://kochetkov.github.io
Дата: 24.10.09 23:12
Оценка:
Здравствуйте, samius, Вы писали:

S>так принято записывать только потому что string->int->Y еще больше не соответсвует действительности.


Нет, не поэтому, а потому что "string*int" читается как "элемент множества, являющегося декартовым произведением множеств значений типов string и int". А элементом декартового произведения двух множеств как раз и является кортеж (в терминологии теории множеств) с парой элементов, принадлежащих каждый своему множеству значений.

[Интервью] .NET Security — это просто
Автор: kochetkov.vladimir
Дата: 07.11.17
Re[3]: Inline records
От: samius Япония http://sams-tricks.blogspot.com
Дата: 25.10.09 05:19
Оценка:
Здравствуйте, kochetkov.vladimir, Вы писали:

KV>Здравствуйте, samius, Вы писали:


S>>так принято записывать только потому что string->int->Y еще больше не соответсвует действительности.


KV>Нет, не поэтому, а потому что "string*int" читается как "элемент множества, являющегося декартовым произведением множеств значений типов string и int". А элементом декартового произведения двух множеств как раз и является кортеж (в терминологии теории множеств) с парой элементов, принадлежащих каждый своему множеству значений.


Про декартово произведение я знаю, не знал лишь что Nemerle может подать кортеж в метод, где параметры объявлены через запятую. F# вот так не может.
Re[10]: Inline records
От: vdimas Россия  
Дата: 25.11.09 12:31
Оценка:
Здравствуйте, lomeo, Вы писали:

L>Выгода использования таплов (при малом количестве полей) проявляется в том, что паттерн получается очень компактным, создание значения тоже, плюс (но это и у записей) — нам не нужно создавать дополнительный тип.


Ну дык есть же концепция анонимных типов в C#. Решают ровно ту же задачу, что и таплы — избавляются от описания дополнительных типов.


L>Очевидно, что в критерии "полей достаточно мало для тапла" есть немного субъективного, т.к. понимание кода вещь тоже субъективная. По моему это и есть место для спора


Да нечего тут спорить. Самодокументируемость кода — это всегда +, хоть с одной переменной, хоть с двумя. Ф-ия, возвращающая 1 результат обычно описывает его своим именем. А если результатов более одного, то надо как-то это имя "раскидать" по ним, что не всегда выливается в разумный баланс м/у эстетичностью имени и однозначностью понимания читателем кода. Даже в случае всего 2-х возвращаемых значений.


V>>По твоему имена аргументов методов хранятся в метаинформации того же дотнет просто так? Ведь можно было бы обойтись хранением в метаинформации только типов (как в obj-файлах C++), а сигнатуру давать в виде хелпа.


L>Я не знаю дотнет. Ты про IDE говоришь в выделенном?


Это было утрирование, на самом деле в дотнете в метаинформации хранится не только сигнатура ф-ии (как в obj-файлах), но и имена аргументов. Ну как хотел бы это видеть примерно показал здесь: http://www.rsdn.ru/forum/philosophy/3571316.1.aspx
Автор: vdimas
Дата: 16.10.09

Ибо в дотнете большая засада в том, что анонимные типы сегодня не являются таплами, т.е. не совместимы м/у собой.


V>>Там где 2-3 поля тупла, вероятность ошибки не высока... но ведь очевидно, что чем больше полей, тем больше требуется удобств.


L>Разумеется, не стоит пользоваться таплами с надцатью полями.


Даже с 2-мя полями, повторюсь, разумнее их именовать. Иначе мы получаем вроде бы "математически минималистическую" запись, которую тут пропагандирует известный хаскелист. Однако, при чтении и поддержке кода практически всегда пофиг суть решения (серьезно), гораздо важнее понимания задачи, которая решается этим кодом. Простым умножением матриц можно решить чуть ли не бесчисленное м-во задач, однако в коде необходимо указывать, какая именно из них решается. Я одно время довольно много просматривал исходников на Хаскеле (из любопытства). И что заметил: пояснения к коду приходилось искать в месте его "клиентского" использования, когда уже конкретным переменным в позициях тапла давались осмысленные имена. Т.е. без этих примеров использования самодокументация кода практически стремится к 0-лю, поэтому с т.з. моего ИМХО тут и нечего обсуждать.
... << RSDN@Home 1.2.0 alpha rev. 786>>
Re[2]: Inline records
От: Alexander Polyakov  
Дата: 28.11.09 20:39
Оценка:
Здравствуйте, Undying, Вы писали:

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

Тут вот какой момент интересен. В Tuple-ах (в C# 4.0) “поля” Item1, Item2 …, ItemN равнозначны. Поскольку они равнозначны, то отсутствие у них нормальных имен вполне естественно (Item1, …, ItemN это, конечно, не нормальные имена, а так затычки). Соответственно, требуется механизм для введения нормальных имен в момент использования Tuple-ов. А вот представить класс с неравнозначными свойствами/методами и чтобы для него потребовалось переименование этих свойств/методов -- мне такое представить сложно. Ты можешь привести реальный пример, где такое требуется? Когда свойства/методы неравнозначны, то они наверняка уже имеют говорящие имена. Иначе как-то странно, свойство имеет некоторый смысл отличный от других свойств, но не имеет нормального имени. А если имена и так уже говорящие, тогда зачем их переименовывать? (см. Примечание 1.)

С другой стороны предложенный тобой способ для задачи “дать имена и типы полям Tuple-а” не является самым удобным.
class MyReturnValue implement Tuple<string, DateTime, Item1 as Name, Item2 as BeginTime>;
Плохо прослеживается, какой тип к какому имени относится. Это происходит из-за того, что тип с именем связывается через посредника Item1, ..., ItemN. Я бы предпочел что-то типа такого
class MyReturnValue implement Tuple
{
    string Name;
    DateTime BeginTime;
}
Правда обычный Tuple в смысле C# 4.0 тут не подойдет. Но я высказал критику с точки зрения пользователя, а над реализацией уже можно думать (варианты есть).

Примечание 1. На самом деле, в одном классе могут существовать несколько групп равнозначных свойств, например, SmallItem1, …, SmallItemN и BigItem1, …, BigItemN. Это, да, такое можно представить, но чтобы все свойства были неравнозначны и не имели нормальных имен -- такое представить сложно.
Re[11]: Inline records
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 29.12.09 21:06
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Ибо в дотнете большая засада в том, что анонимные типы сегодня не являются таплами, т.е. не совместимы м/у собой.


Совместимы. Но только в пределах одной сборки.
... << RSDN@Home 1.2.0 alpha 4 rev. 1324 on Windows 7 6.1.7600.0>>
AVK Blog
Re[11]: Inline records
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 30.12.09 07:30
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Даже с 2-мя полями, повторюсь, разумнее их именовать. Иначе мы получаем вроде бы "математически минималистическую" запись, которую тут пропагандирует известный хаскелист. Однако, при чтении и поддержке кода практически всегда пофиг суть решения (серьезно), гораздо важнее понимания задачи, которая решается этим кодом. Простым умножением матриц можно решить чуть ли не бесчисленное м-во задач, однако в коде необходимо указывать, какая именно из них решается. Я одно время довольно много просматривал исходников на Хаскеле (из любопытства). И что заметил: пояснения к коду приходилось искать в месте его "клиентского" использования, когда уже конкретным переменным в позициях тапла давались осмысленные имена. Т.е. без этих примеров использования самодокументация кода практически стремится к 0-лю, поэтому с т.з. моего ИМХО тут и нечего обсуждать.


Я понял твою мысль. И скорее согласен, но случаи разные бывают. В том же Хаскеле переменные/параметры гораздо менее важны, чем в С#, а типы более важны, потому что выразить через них можно (удобнее) больше. Поэтому таплы там к месту — имена вполне заменяют типы.

http://www.haskell.org/hoogle/?hoogle=a+-%3E+%28b%2Cc%29

По типам сразу видно что где возвращается. Там, где типы одинаковые, всё равно ясно из контекста — это или split (span и т.д.), т.е. делим на левое и правое, или диапазон (genRange), т.е. начало и конец. Не нужны там имена для параметров.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.