А в C# 3.0 тоже так?

shlyumper

CS1628: Cannot use ref or out parameter 'parameter' inside an anonymous method block
Гугление выдает чьи-то домыслы о том, что де так будет всегда, т.к. необходимые для реализации концепции не предусмотрены в managed code. Кто читал C# 3.0, там все так же печально?
Ну и любопытство: F#/Nemerle этого обходить тоже не умеют?

Dasar

> CS1628: Cannot use ref or out parameter 'parameter' inside an anonymous method block
что должен делать вот такой код?:
падать по Core dumped?

void Main
{
if(..)
{
int i;
Calculate(out i);
}
Console.ReadLine;
}
void Calculate(out i)
{
Thread thread = new Thread(delegate
{
Thread.Sleep(TimeSpan.FromSeconds(10;
i = 5;
});
thread.Start;
}

т.е. основная проблема в том, что out/ref параметры не имеют смысла вне текущего контекста,
а anonymous block как раз может быть передан за текущий контекст.

shlyumper

Это отмазка. Я ж не с потолка это взял, существует достаточное количество случаев, когда это было бы полезно, и функция выполнялась бы в контексте того же треда. И смысл как раз в том, чтобы передать анонимный блок за пределы текущего контекста; "имеет ли это смысл" - решает программист, компилятор в данном случае ошибается.
Я уж не говорю о том, что такую функциональность можно получить в любом случае через внешние глобальные переменные.
А вопрос возник примерно из такого желания:

class SomeForm
{
SomeForm
{
...
button1.Clicked += validate_bitmap_button(textPathTop, out bmpTop);
button2.Clicked += validate_bitmap_button(textPathMiddle, out bmpMiddle);
button3.Clicked += validate_bitmap_button(textPathBottom, out bmpBottom);
...
}

EventHandler validate_bitmap_button(TextBox path, out Bitmap bmp)
{
return new EventHandler(delegate(object sender, EventArgs e)
{
try {
bmp = ValidateAndLoadBitmap(path.Text);
// Чтобы сделать validate, bitmap надо загрузить. Зачем потом грузить его еще раз?
} catch(FileIsInvalidForOurTask) {
//...
}
});
}
}

В том же Perl'е такое не считается "не имеющим смысла вне текущего контекста". Это удобно.

kokoc88

// Чтобы сделать validate, bitmap надо загрузить. Зачем потом грузить его еще раз?
А зачем каждый раз при клике грузить битмап?

shlyumper

По условаию задачи при клике надо сделать validate. Для того чтобы его сделать, bitmap надо загрузить.
Ты уводишь разговор в сторону. Существует еще много случаев, когда такая функциональность удобна.
P.S. Вспоминается http://www.paulgraham.com/accgen.html

Marinavo_0507

Ну и любопытство: F#/Nemerle этого обходить тоже не умеют?
а там есть out-параметры?

shlyumper

Ну и любопытство: F#/Nemerle этого обходить тоже не умеют?
а там есть out-параметры?
Понятия не имею. Подозреваю, что там что-то такое можно организовать.

Marinavo_0507

В *ML нужно явно объявлять переменную i по-другому (ссылкой).
Наверное, и в F# так же.
Это - явное указание компилятору, что с такой переменной нужно поступать по-другому. Наверное, C# пытается локальные переменные размещать на стеке.

kokoc88

По условаию задачи при клике надо сделать validate. Для того чтобы его сделать, bitmap надо загрузить.
Я просто хочу сказать, что вовсе не обязательно загружать картинку каждый раз при клике.
Ты уводишь разговор в сторону. Существует еще много случаев, когда такая функциональность удобна.
P.S. Вспоминается http://www.paulgraham.com/accgen.html

По ссылке я не нашёл этой функциональности. Там обычный closure.

6yrop

Ты уводишь разговор в сторону.
Возможно, но, имхо, если реализовать это в java-стиле (где нет делегатов и out-параметров то будет даже лучший дизайн.

shlyumper

Я просто хочу сказать, что вовсе не обязательно загружать картинку каждый раз при клике.
Тьфу привязался. Ну по условию задачи так. Это не "нравится - не нравится". В любом случае, я просто привел пример, когда out параметр в anonymous delegate имеет смысл. И у меня особого желания мусолить насколько это политкорректно - использовать такие конструкции - нет. Вопрос же простой:
А в C# 3.0 тоже так?

shlyumper

Возможно, но, имхо, если реализовать это в java-стиле (где нет делегатов и out-параметров то будет даже лучший дизайн.
А можно пример, как это сделать in java way? Я java знаю на уровне читателя, не писателя.

shlyumper

По ссылке я не нашёл этой функциональности. Там обычный closure.
В C# 2.0 closure поддерживается только в виде anonymous delegates, или я что-то не понимаю?

kokoc88

Ну по условию задачи так.
То есть я кликнул на кнопку один раз, а когда кликал во второй - картинку уже стёрли? А где она нужна, чтобы "не загружать её во второй раз"? Ты описываешь какой-то изощрённый вариант closure.

shlyumper

Никаких изощрений. Ну что ты к файлам привязался? Ну хочешь, пусть так будет:

class Accumulators {
string s1, s2, s3;
Accumulators {
button1.Click += accumulate_to(out s1);
button2.Click += accumulate_to(out s2);
button3.Click += accumulate_to(out s3);

button4.Click += new EventHandler(delegate(object sender, EventArgs e)
{
MessageBox.Show(string.format("s1: {0}, s2: {1}, s3: {2}", s1, s2, s3;
});
}

EventHandler accumulate_to(out string s) {
return new EventHandler(delegate(object sender, EventArgs e {
s += "Yo!";
}
}
}

kokoc88

Никаких изощрений. Ну что ты к файлам привязался? Ну хочешь, пусть так будет:
Вот, теперь более понятно. Просто по ссылке описано замыкание на параметр, а сам параметр при этом не трогают. Ты же хочешь изменять содержимое ссылки. Да, придётся оборачивать изменяемую ссылку.

Marinavo_0507

а зачем надо писать accumulate_to(out s1 когда в прототипе уже есть out?

shlyumper

The out keyword causes arguments to be passed by reference. This is similar to the ref keyword, except that ref requires that the variable be initialized before being passed. To use an out parameter, both the method definition and the calling method must explicitly use the out keyword.

Dasar

> Я ж не с потолка это взял, существует достаточное количество случаев, когда это было бы полезно, и функция выполнялась бы в контексте того же треда. И смысл как раз в том, чтобы передать анонимный блок за пределы текущего контекста; "имеет ли это смысл" - решает программист, компилятор в данном случае ошибается
так основной вопрос: ни что делать, когда все хорошо, а что делать если все-таки эта переменная разрушена?
т.е. ты хочешь, чтобы .net портил память?

Marinavo_0507

зачем её разрушать, когда на неё ещё есть ссылки?
сборщик мусора нафига?

shlyumper

Во-первых, см. ответ , во-вторых, делать runtime exception. Подход "мы не дадим вам такую удобную фичу, потому что с ее помощью можно написать некорректную программу?
Я уж не говорю о том, что это ограничение фактически обходится при помощи костылей как-то так, например:

class a {
int[] many_i;
void Main
{
if(..)
{
int i;
Calculate(i_index);
}
Console.ReadLine;
}
void Calculate(int i_index)
{
Thread thread = new Thread(delegate
{
Thread.Sleep(TimeSpan.FromSeconds(10;
many_i[i_index] = 5;
});
thread.Start;
}

Ну или на моем примере:

class Accumulators {
string[] many_s;
Accumulators {
many_s = new string[3];
button1.Click += accumulate_to(0);
button2.Click += accumulate_to(1);
button3.Click += accumulate_to(2);

button4.Click += new EventHandler(delegate(object sender, EventArgs e)
{
MessageBox.Show(string.format("s1: {0}, s2: {1}, s3: {2}", many_s[0], many_s[1], many_s[2];
});
}

EventHandler accumulate_to(int s_index) {
return new EventHandler(delegate(object sender, EventArgs e {
many_s[s_index] += "Yo!";
}
}
}

Только оба эти варианта получаются менее читаемыми, чем могли бы...

Dasar

> см. ответ ,
его предложение тянет за собой, что .net должен следит за каждой value-переменной, а это за собой тянет ощутимые провалы по скорости работы.
> во-вторых, делать runtime exception
каким образом будет осуществляться эта проверка?
как твой пример будет работать, если метод Calculate находится уже в скомпилированном методе?

Marinavo_0507

его предложение тянет за собой, что .net должен следит за каждой value-переменной
опять неверно
http://en.wikipedia.org/wiki/Escape_analysis

shlyumper

его предложение тянет за собой, что .net должен следит за каждой value-переменной,
... на этапе компиляции. В runtime нужно следить только за некоторыми. И?
каким образом будет осуществляться эта проверка?
Не потребуется, если сделать все правильно. Если же не следить за переменными - то наверняка есть такое понятие, как invalid reference или что-то такое?
Еще по обоим замечаниям: это же умеют делать в других языках, без больших потерь производительности. См. accumulator benchmark по ссылке в моих постах выше.
как твой пример будет работать, если метод Calculate находится уже в скомпилированном методе?
Поясни вопрос?

Dasar

> Поясни вопрос?
ты забываешь о том, что метод Calculate может быть описан в другом модуле, который уже скомпилирован до byte-кода, и может быть даже уже запущен и скомпилирован до native-кода.
твой код с anonymous блоком подгружается может быть вообще динамически через несколько дней после запуска Calculate-метода.
или другими словами не надо забывать, что слова out/ref и так далее, это не слова языка, это слова виртуальной машины, соответственно язык (в данном случае C#) не может эти слова заменить на какое-то свое шаманское поведение.

Marinavo_0507

ты забываешь о том, что метод Calculate может быть описан в другом модуле, который уже скомпилирован до byte-кода, и может быть даже уже запущен и скомпилирован до native-кода.
и что?
в прототипе написано out, то есть VM заранее знает, за чем нужно особенно следить

kokoc88

Еще по обоим замечаниям: это же умеют делать в других языках, без больших потерь производительности. См. accumulator benchmark по ссылке в моих постах выше.
То, что у тебя по ссылке - это совсем другая задача. Совсем не то, что ты хочешь сделать в своей программе. Аккумулятор делает замыкание, которое хранит переменную внутри себя. И увеличивает её. Внешние ссылки и объекты не модифицируются.

shlyumper

Короче, ты и пытаетесь отмазаться что типа "такого не бывает", и вы не правы.
В гугле считают, что такого не бывает лишь по той причине, что не предусмотрен в текущем дотнете тип "reference to a reference".
Был бы этот тип - тогда было бы на порядок меньше проблем. Любой out параметр был бы reference, валидация жизни объектов, которая тебя так напрягает, была бы простой, как-то так:
1. dereference.
2. получили value-type? отлично, изменили.
3. получили reference-type? reference жив? отлично, изменили.
4. выкинули exception.
Еще раз напоминаю, вопрос был не в том "почему этого нету в C# 2.0", и не "почему это плохо, и этого не надо", а "будет ли/есть ли это в C# 3.0, и является ли его отсутсвие сейчас - ограничением дотнет платформы в целом". Флудеры, блин...

Dasar

я тебе как раз пытаюсь объяснить, что отсутствие типа ref to ref - это ограничение виртуальной машины .net-платформы.
к языку C# это ограничение никакого отношения не имеет.
соответственно в C# 3.0 ничего не изменится, т.к. при выходе C# 3.0 никто VM менять не будет.

Dasar

> что не предусмотрен в текущем дотнете тип "reference to a reference".
фактически он есть- это delegate
т.е. то, что ты хочешь записывается так:

class SomeForm
{
SomeForm
{
...
button1.Clicked += validate_bitmap_button(textPathTop, delegate(Bitmap bmp){bmpTop=bmp;});
button2.Clicked += validate_bitmap_button(textPathMiddle, delegate(Bitmap bmp){bmpMiddle=bmp;});
button3.Clicked += validate_bitmap_button(textPathBottom, delegate(Bitmap bmp){bmpBottom=bmp;});
...
}

EventHandler validate_bitmap_button(TextBox path, Execute<Bitmap> bmpRef)
{
return new EventHandler(delegate(object sender, EventArgs e)
{
try {
bmpRef(ValidateAndLoadBitmap(path.Text;
// Чтобы сделать validate, bitmap надо загрузить. Зачем потом грузить его еще раз?
} catch(FileIsInvalidForOurTask) {
//...
}
});
}
}


на C# 3.0

button1.Clicked += validate_bitmap_button(textPathTop, bmp => bmpTop=bmp;);

Dasar

другими словами out/ref - это низкоуровневые шняги необходимые для генерация очень оптимального кода.
на верхнем уровне, вместо out/ref удобнее использовать делегаты, как в тех же самых ФЯ.

bastii

поддерживаю
ref и out — это фактически возможность использовать & из C++, но в ограниченных ситуациях, когда это может привести к нарушению свойств managed code в .NET
Так в .NET есть возможность ссылаться на значения, которые находятся в стеке. По идее это позволяет, например, для рекурсивного алгоритма хранить в стеке список с какими-то данными от каждого вызова в последовательности вложенных вызовов. В Джава придется использовать кучу, что в некоторых случаях дает неприемлемую нагрузку на GC. В результате приходиться структуру кэшировать в объекте, что вызывает проблемы, когда этот объект используется множеством потоков, приходиться извращаться дальше.

kokoc88

Короче, ты и пытаетесь отмазаться что типа "такого не бывает", и вы не правы.
Нет, никто не пытается отмазаться. Дарк хочет сказать о том, что невыгодно считать ссылки на value типы. Я хочу сказать, что твой пример по ссылке делает не то, что ты хочешь в топике.
Оставить комментарий
Имя или ник:
Комментарий: