Re[5]: Замыкания
От: Ziaw Россия  
Дата: 29.01.11 16:15
Оценка: 1 (1)
Здравствуйте, BogdanMart, Вы писали:

BM>а в этом случи на Слабо связаный ивент подписываеться метод объекта, который сздался локально, и ссылок на него нигде нету. вот он и убереться сборщиком мусора..


BM>Ну как-бы ситуация не очень ординарная, но с другой стороны с этими функциями перемудрили где-то. Можно было и по проще сделать первоклассные функции.


При работе со слабыми ссылками, ты должен учитывать, что объект на который она ссылается в любой момент просто исчезнет. Я не очень понимаю, в чем собственно проблема способа генерации замыканий в nemerle. Решение очень похоже на неудачный архитектурный костыль.
Re[10]: Замыкания
От: Ziaw Россия  
Дата: 29.01.11 18:54
Оценка: +1
Здравствуйте, BogdanMart, Вы писали:

BM>BogdanMart писал:


BM>>В слабой ссылке лежит Target делегата


Я понял, в дотнете есть штатный механизм, позволяющий гарантировать отсутствие проблем с GC при правильной работе с делегатами и событиями и ты этот механизм ломаешь намеренно. Грабли обеспечены, на одни ты уже наступил, то, что шарп делает сейчас приватным методом, при небольшой модификации кода превратится в объект замыкания, ты даже не поймешь что произошло, когда программа начнет падать в непредсказуемых местах.
Re[12]: Замыкания
От: Ziaw Россия  
Дата: 29.01.11 19:12
Оценка: +1
Здравствуйте, BogdanMart, Вы писали:

Z>>Я понял, в дотнете есть штатный механизм, позволяющий гарантировать отсутствие проблем с GC при правильной работе с делегатами и событиями.

BM>С этоо места, пожалуйста, по подробнее!

Да ты сам прекрасно его знаешь, делегат держит ссылку на таргет и не дает сборщику его собрать. Если мы можем как-то обратиться к объекту, значит он не будет собран.

Z>> Gри небольшой модификации кода превратится в объект замыкания, ты даже не поймешь что произошло

BM>Я то пойму.. замікания шарю хорошо, да и не надо его менять. (но в целом самому создать метод надежнее, безусловно, так и сделал..)

Это ты сейчас поймешь, а через год-другой сильно удивишься, ибо падения начнутся совсем не сразу после невинной модификации кода, которую сделаешь, возможно, совсем не ты
Re[5]: Замыкания
От: catbert  
Дата: 30.01.11 15:16
Оценка: +1
Здравствуйте, BogdanMart, Вы писали:

BM>Ну как-бы ситуация не очень ординарная, но с другой стороны с этими функциями перемудрили где-то. Можно было и по проще сделать первоклассные функции.


Проблемы производительности — это одно. Но если правильность вашего кода зависит от реализации компилятора, это уже другое, намного хуже.

Что будет с вашим кодом, если в Редмонде тоже решат, что "объекты быстрее делегатов" и изменят реализацию лямбд? Что будет, если вы захотите скомпилировать ваш код на Mono C#, где компилятор по-другому создает ламбды?

Я сомневаюсь (хотя чесно говоря, не смотрел), что в спецификации описано, как в C# создаются анонимные функции.
Замыкания
От: BogdanMart Украина  
Дата: 28.01.11 21:58
Оценка:
Както по дебильному немерле генерит замыкания
                  def param = getOmmParameter(Guid($(param.ID.ToString() : string))); // ну тут макрос, но можете счиатать что это строка "66d1a69e-37d2-4569-9c81-3dc0b441d4a5"
                  param.PropertyChanged += fun(_, e)
                  {
                    when (e.PropertyName == "Value")
                      OnPropertyChanged((param.Name : string));
                  }
                  
                  param.Value :> $(param.Type.ToString() : usesite)
                }



и на вызоде получается

    get
    {
        _N_closure_8066 e_ = new _N_closure_8066 {
            _N__N_closurised_this_ptr_8071 = this,
            _N_param_8073 = this.getOmmParameter(new Guid())
        };
        FunctionVoid<object, PropertyChangedEventArgs> @void = new _N__N_lambda__8057__8075(e_);
        e_._N_param_8073.PropertyChanged += new PropertyChangedEventHandler(@void.apply_void);
        return (double) e_._N_param_8073.Value;
    }



Вопроссы
1) зачем Гуид пихать в замыкание? Если он ипсользуеться только в теле метода..
2) Зачем вообще создавать класс _N__N_lambda__8057__8075, C# создает в таком случаае приватный метод с рандомным именем, и подписывает на событие делегат на этот метод.

Я бы не возущался... но есть один нюанс, мы используем WeakDelegatе и по этому _N__N_lambda__8057__8075 запроста уберется сборщиком мусора... очень печально.

Это создавать целый метод для такой тривиальной задачи... а шарп справлялся...
Re: Замыкания
От: BogdanMart Украина  
Дата: 28.01.11 22:12
Оценка:
Здравствуйте, BogdanMart, Вы писали:

BM>Както по дебильному немерле генерит замыкания

BM>
BM>                  def param = getOmmParameter(Guid($(param.ID.ToString() : string))); // ну тут макрос, но можете счиатать что это строка "66d1a69e-37d2-4569-9c81-3dc0b441d4a5"
BM>                  param.PropertyChanged += fun(_, e)
BM>                  {
BM>                    when (e.PropertyName == "Value")
BM>                      OnPropertyChanged((param.Name : string));
BM>                  }
                  
BM>                  param.Value :> $(param.Type.ToString() : usesite)
BM>                }
BM>



BM>1) зачем Гуид пихать в замыкание? Если он ипсользуеться только в теле метода..



Про замыкание для гуида вопрос снимаеться... забылся поставить $ перед (param.Name : string)
Re: Замыкания
От: hardcase Пират http://nemerle.org
Дата: 28.01.11 22:46
Оценка:
Здравствуйте, BogdanMart, Вы писали:

BM>Я бы не возущался... но есть один нюанс, мы используем WeakDelegatе и по этому _N__N_lambda__8057__8075 запроста уберется сборщиком мусора... очень печально.


Почему она запросто соберется сборщиком мусора?
/* иЗвиНите зА неРовнЫй поЧерК */
Re[2]: Замыкания
От: BogdanMart Украина  
Дата: 29.01.11 10:29
Оценка:
Здравствуйте, hardcase, Вы писали:

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


BM>>Я бы не возущался... но есть один нюанс, мы используем WeakDelegatе и по этому _N__N_lambda__8057__8075 запроста уберется сборщиком мусора... очень печально.


H>Почему она запросто соберется сборщиком мусора?


мы используем WeakDelegatе, по этому эта строка e_._N_param_8073.PropertyChanged += new PropertyChangedEventHandler(@void.apply_void); не создает ссылку на объект, и после выхода из текущего метода функция за коллектиться, а Шарп в этом случае просто создает метод в текущем классе и его подписывает...

Конечно никто не рассчитывал Немерле на WeakDelegatы, но все ровно не особо оптимально использовать Функцию, если она все ровно конвериться в делегат и скармливается ивенту.

Просто удивляет, что люди доказывают что Функции быстрее делегатов... а под капотом немерле такое вытворяет с замыканиями... что аж страшно.

Чистые функции может и быстрее, но обычные иногда создают лишнее замыкание.
Re: Замыкания
От: catbert  
Дата: 29.01.11 10:43
Оценка:
Здравствуйте, BogdanMart, Вы писали:

BM>2) Зачем вообще создавать класс _N__N_lambda__8057__8075, C# создает в таком случаае приватный метод с рандомным именем, и подписывает на событие делегат на этот метод.


Делегаты медленные.

BM>Я бы не возущался... но есть один нюанс, мы используем WeakDelegatе и по этому _N__N_lambda__8057__8075 запроста уберется сборщиком мусора... очень печально.


Это почему?

BM>Это создавать целый метод для такой тривиальной задачи... а шарп справлялся...


Объект, вы хотите сказать? Но делегат (который возвращается в C#) тоже объект. А без создания метода в .NET наверное никак.
Re[2]: Замыкания
От: BogdanMart Украина  
Дата: 29.01.11 10:48
Оценка:
Здравствуйте, catbert, Вы писали:



BM>>Я бы не возущался... но есть один нюанс, мы используем WeakDelegatе и по этому _N__N_lambda__8057__8075 запроста уберется сборщиком мусора... очень печально.


C>Это почему?


На этот вопрос я ответил хардкейсу

BM>>Это создавать целый метод для такой тривиальной задачи... а шарп справлялся...


C>Объект, вы хотите сказать? Но делегат (который возвращается в C#) тоже объект. А без создания метода в .NET наверное никак.


Я имел ввиду создавать метод вручную, когда шарп сам из лямбды создает метод, а не класс-функцию.

Пришлось сделать так

decl:
              private $(event_watcher : name) (_ : object, e : System.ComponentModel.PropertyChangedEventArgs) : void
              {
                when (e.PropertyName == "Value")
                  OnPropertyChanged($(param.Name : string));
              }

                get
                {
                  def param = getOmmParameter(Guid($(param.ID.ToString() : string)));
                  param.PropertyChanged += $(event_watcher : name);
                  
                  param.Value :> $(param.Type.ToString() : usesite)
                }


Казалось бы лишний метод создать, но где автоматизация..
Re[3]: Замыкания
От: hardcase Пират http://nemerle.org
Дата: 29.01.11 11:33
Оценка:
Здравствуйте, BogdanMart, Вы писали:

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


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


BM>>>Я бы не возущался... но есть один нюанс, мы используем WeakDelegatе и по этому _N__N_lambda__8057__8075 запроста уберется сборщиком мусора... очень печально.


H>>Почему она запросто соберется сборщиком мусора?


BM>мы используем WeakDelegatе, по этому эта строка e_._N_param_8073.PropertyChanged += new PropertyChangedEventHandler(@void.apply_void); не создает ссылку на объект, и после выхода из текущего метода функция за коллектиться, а Шарп в этом случае просто создает метод в текущем классе и его подписывает...


Еще раз, для тупых. PropertyChangedEventHandler захватит только адрес apply_void метода без замыкания?
/* иЗвиНите зА неРовнЫй поЧерК */
Re: Замыкания
От: hardcase Пират http://nemerle.org
Дата: 29.01.11 11:37
Оценка:
Здравствуйте, BogdanMart, Вы писали:

BM>Вопроссы

BM>1) зачем Гуид пихать в замыкание? Если он ипсользуеться только в теле метода..

Это косяк оптимизации замыканий.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[4]: Замыкания
От: BogdanMart Украина  
Дата: 29.01.11 12:04
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Еще раз, для тупых. PropertyChangedEventHandler захватит только адрес apply_void метода без замыкания?


WeakDelegate это объект который хрпнит в себесписок WeakReferenc'ов на объекты и список указателей на методы (не MatdodInfo а згенереный в рантайем динамический метод, который делает вызов) что позволяет объектам которые подпись на событие благополучно убераться сборщикоммусора. (Оно из делегата извлекает MethodInfo и ссылку на объект и преобразовывает их). Удобство Вик деоегато в первую очередь при работе с гуишкой. Например листобкс при устанвке в качестве ItemsSource коллекции подписываеться на событие CollectionChanged. а при уберании колеекции из ItemsSource НЕ ОТПИСЫВАЕТЬСЯ(Майровсойт -- мудаки), но даже еслибы он и отписывался при убирании из ИтемзСоурс, то при закрытии формочки она всеровно не убераеться, потому что делегат CollectionChanged содержыт ссылку на формочку. По этому и розработали ВикДелегаты.

а в этом случи на Слабо связаный ивент подписываеться метод объекта, который сздался локально, и ссылок на него нигде нету. вот он и убереться сборщиком мусора..

Ну как-бы ситуация не очень ординарная, но с другой стороны с этими функциями перемудрили где-то. Можно было и по проще сделать первоклассные функции.
Re[6]: Замыкания
От: hardcase Пират http://nemerle.org
Дата: 29.01.11 16:26
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>При работе со слабыми ссылками, ты должен учитывать, что объект на который она ссылается в любой момент просто исчезнет.


Объект чей метод подписывается — это экземпляр функции (fun), создался он изза того, что компилятор решил что ссылка на него кудато уходит (подписывается событие).
Понятно что слабая ссылка на этот промежуточный объект функции не учитывается при сборке мусора и функция благополучно собирается сборщиком мусора. В итоге мы имеем то, что основной объект которому нжуно получать уведомления еще существует, но уведомлений он не получает — GC уже собрал экземпляр функции (на него не осталось ссылок).
/* иЗвиНите зА неРовнЫй поЧерК */
Re[6]: Замыкания
От: BogdanMart Украина  
Дата: 29.01.11 18:15
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z> Решение очень похоже на неудачный архитектурный костыль.


Ну как бы создал метод и на него генерирую делегат.. Просто было лень метод создавать но вообще просто не понятно зачем немерлу генерить замыкание, если можно создать приватный метод и вместо замыкания использовать this
Re[7]: Замыкания
От: Ziaw Россия  
Дата: 29.01.11 18:27
Оценка:
Здравствуйте, hardcase, Вы писали:

Z>>При работе со слабыми ссылками, ты должен учитывать, что объект на который она ссылается в любой момент просто исчезнет.


H>Объект чей метод подписывается — это экземпляр функции (fun), создался он изза того, что компилятор решил что ссылка на него кудато уходит (подписывается событие).

H>Понятно что слабая ссылка на этот промежуточный объект функции не учитывается при сборке мусора и функция благополучно собирается сборщиком мусора. В итоге мы имеем то, что основной объект которому нжуно получать уведомления еще существует, но уведомлений он не получает — GC уже собрал экземпляр функции (на него не осталось ссылок).

В слабой ссылке лежит делегат, как я понял. Ну так это обычное поведение слабой ссылки, этот делегат может стать недоступным в любой момент, вне зависимости от того, какому объекту этот метод принадлежит.
Re[8]: Замыкания
От: BogdanMart Украина  
Дата: 29.01.11 18:30
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>В слабой ссылке лежит делегат, как я понял. Ну так это обычное поведение слабой ссылки, этот делегат может стать недоступным в любой момент, вне зависимости от того, какому объекту этот метод принадлежит.


В слабой ссылке лежит Target делегата
Re[9]: Замыкания
От: BogdanMart Украина  
Дата: 29.01.11 18:36
Оценка:
BogdanMart писал:

BM>В слабой ссылке лежит Target делегата


часть кода вик делегата
        public void Add(TDelegate @delegate)
        {
            if (@delegate != null)
                lock (dels)
                    foreach (var del in ((Delegate)(object)@delegate).GetInvocationList())
                    {
                        var method = del.Method;
                        if(method.IsStatic)
                            _invk = Delegate.Combine(_invk , del);
                        else
                            dels.Add(new Tuple<WeakReference, Func<object, object[], object>, MethodInfo>(new WeakReference(del.Target), method.GetInvokator(), method));
                    }
        }


Где .GetInvokator()
        public static Func<object, object[], object> GetInvokator(this MethodInfo mi)
        {
            lock (cache)
            {
                Func<object, object[], object> fun;
                if (cache.TryGetValue(mi, out fun))
                    return fun;
                
                var method = new DynamicMethod("_" + r.Next(), typeof(object), _args,
                                               typeof (InvokatorFactory), true);

                var generator = method.GetILGenerator();
                var helper = new EmitHelper(generator);
                var parameters = mi.GetParameters();
                var len = parameters.Length;
                //--------------------
                if (!mi.IsStatic)
                    helper
                        .ldarg_0
                        .castclass(mi.DeclaringType);
                //--------------------
                for (int i = 0; i < len; i++)
                    helper
                        .ldarg_1
                        .ldc_i4_(i)
                        .ldelem_ref
                        .CastFromObject(parameters[i].ParameterType);
                //--------------------
                helper
                    .call(mi)
                    .parseRet(mi.ReturnType)
                    .ret();
                

                fun = (Func<object, object[], object>) method.CreateDelegate(typeof (Func<object, object[], object>));
                cache.Add (mi, fun);

                return fun;
            }
        }


По сути GetInvokator генерирует для метода M функцию (obj, params) => obj.M(params[0],..., params[n])
Re[7]: Замыкания
От: Ziaw Россия  
Дата: 29.01.11 18:41
Оценка:
Здравствуйте, BogdanMart, Вы писали:

Z>> Решение очень похоже на неудачный архитектурный костыль.


BM>Ну как бы создал метод и на него генерирую делегат.. Просто было лень метод создавать но вообще просто не понятно зачем немерлу генерить замыкание, если можно создать приватный метод и вместо замыкания использовать this


Ну если кроме this в замыкании ничего нет, то так и надо делать, но у тебя что-то еще туда пихается. Но главная проблема в использовании WeakReference не по назначению. Баги майкрософта конечно неприятные, но обходятся они без weakreference, который породит в этой ситуации баги похлеще. Можно обойтись спецколлекцией, которая проверяет кто на нее подписался и подписывается на диспоуз листбокса.
Re[8]: Замыкания
От: BogdanMart Украина  
Дата: 29.01.11 18:43
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>Можно обойтись спецколлекцией, которая проверяет кто на нее подписался и подписывается на диспоуз листбокса.


ВО! , хреново.
Re[11]: Замыкания
От: BogdanMart Украина  
Дата: 29.01.11 19:01
Оценка:
Здравствуйте, Ziaw, Вы писали:

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


BM>>BogdanMart писал:


BM>>>В слабой ссылке лежит Target делегата


Z>Я понял, в дотнете есть штатный механизм, позволяющий гарантировать отсутствие проблем с GC при правильной работе с делегатами и событиями.

С этоо места, пожалуйста, по подробнее!

Z> Gри небольшой модификации кода превратится в объект замыкания, ты даже не поймешь что произошло

Я то пойму.. замікания шарю хорошо, да и не надо его менять. (но в целом самому создать метод надежнее, безусловно, так и сделал..)
Re[12]: Замыкания
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.01.11 13:39
Оценка:
Здравствуйте, BogdanMart, Вы писали:

Z>> Gри небольшой модификации кода превратится в объект замыкания, ты даже не поймешь что произошло

BM>Я то пойму.. замікания шарю хорошо, да и не надо его менять. (но в целом самому создать метод надежнее, безусловно, так и сделал..)

Я согласен с Ziaw. Если ты хочешь надежной работы, то ссылку на лямбду которую ты хочешь поместить в "слабое событие" нужно "прникапывать" в поле того объекта который подписывается на событие. Иначе ничего гарантировать нельзя. Твой код будет зависеть от фазы луны и направления ветра. Рано или поздно у тебя начнутся глюки которые ты, возможно, даже не сможешь понять.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Замыкания
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.01.11 13:49
Оценка:
Здравствуйте, BogdanMart, Вы писали:

BM>Както по дебильному немерле генерит замыкания


Все генерируется верно. У тебя просто ошибка в коде:
BM>
BM>                      OnPropertyChanged((param.Name : string));
BM>


BM>2) Зачем вообще создавать класс _N__N_lambda__8057__8075, C# создает в таком случаае приватный метод с рандомным именем, и подписывает на событие делегат на этот метод.


Н1 генерирует функциональный объект при следующих условиях:
1. Функция используется как функция высшего порядка (ФВП) — это как раз твой случай.
2. Функция используется более одного раза и при этом она захватывает внешний контекст (создает замыкание).

К сожалению, компилятор Н1 иногда осторожничает и делает функциональным объектом то что можно было бы сделать методом. Это не доработка, но исправление ее осложнено тем, что код там очень мутный. В Н2 можно довести этот вопрос до совершенства.

BM>Я бы не возущался... но есть один нюанс, мы используем WeakDelegatе и по этому _N__N_lambda__8057__8075 запроста уберется сборщиком мусора... очень печально.


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

BM>Это создавать целый метод для такой тривиальной задачи... а шарп справлялся...


Создание метода тоже не очень хорошее решение, так как код будет зависеть от реализации. Лучше просто сделай явную ссылку. Это стопроцентная гарантия.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Замыкания
От: BogdanMart Украина  
Дата: 30.01.11 15:04
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Все генерируется верно. У тебя просто ошибка в коде:

BM>>
BM>>                      OnPropertyChanged((param.Name : string));
BM>>


Да, это я заметил:

BM>> Про замыкание для гуида вопрос снимаеться... забылся поставить $ перед (param.Name : string)

(первый ответ на пост)

Но в целом, да. Ты прав! как-то тупонул.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.